劃分樹小結

2021-06-13 08:35:11 字數 2256 閱讀 3770

最近學習了一下劃分樹,下面總結一下。

我們在求區間最值的時候,一般可以用線段樹解決,但是如果要求區間第k小或者第k大值的話線段樹就有點力不從心了,這是我們可以用劃分樹來解決。劃分樹利用了快速排序的思想,首先是建樹,我們設當前區間的中位數為mid,(為了能快速找到區間的中位數,我們一般先對原序列做一次排序)則我們將區間中比mid小的放入左子樹,將區間中比mid大數的放入右子樹中,和mid相等的要討論一下,有些需要放到左子樹中,其他的放到右子樹中,注意我們將數字放入子樹的時候其相對順序是不變的

。這樣我們一層一層下去,每次區間都減半,則空間消耗為o(nlogn)。下面看乙個例子。

假設序列長度為9,依次為 3 5 7 3 4 9 4 2 5,怎我們看看建樹完成後是什麼樣子。

sort[ ][2  3  3  4  4  5  5  7  9]

tree[0][3  5  7  3  4  9  4  2  5]

tree[1][3  3  4  4  2][5  7  9  5]

tree[2][3  3  2][4  4][5  5][7  9]

tree[3][3  2][3][4][4][5][5][7][9]

tree[4][2][3][3][4][4][5][5][7][9]

好了,樹建完了,接下來就是最關鍵的查詢了,我們設函式query(p,l,r,s,t,k)表示在第p層子樹區間範圍在[l,r]的子樹中查詢區間[s,t]中的第k小值。我們在每一顆子樹中設sum[i]表示區間[l,i]範圍內有多少個數字被放到了左子樹中,那麼我們容易得到,sum[t]-sum[s-1]表示在區間

[s,t]有多少個樹被放入了左子樹中,我們不妨設這個值為num,若k<=num,我們就可以知道我們要找的數一定在左子樹中,否則一定在右子樹中,我們接下來只要繼續往下遍歷,當l==r的時候我們就可以確定我們要找的數,容易知道這一步驟的複雜度為o(log n),現在關鍵的一點就是如何再往下便利的時候確定ls,t的值。這個其實自己畫畫圖就很容易推出來的,下面只寫結論,這裡先設區間[l,s-1]中被放入左子樹的數有snum個,當前區間的中點為mid,

則若k<=num,我們返回query(p+1,l,mid,l+snum,l+sum[t]-1,k),(要找的數在左子樹上)

否則,我們返回query(p+1,mid+1,r,mid+1-l+s-snum,mid+1-l+t-sum[t],k-num

);(要找的數在右子樹上)

下面再舉個例子,數和上面一樣

我們現在要找到區間[2,7]中的第3小數。

sort[ ][2  3  3  4  4  5  5  7  9]

tree[0][3  5  7  3  4  9  4  2  5]

tree[1][3  3  4  4  2][5  7  9  5]

tree[2][3  3  2][4  4][5  5][7  9]

tree[3][3  2][3][4][4][5][5][7][9]

tree[4][2][3][3][4][4][5][5][7][9]

以上橙黃色背景的數字即為我們要求的範圍。

我們首先在第一層樹上尋找,即query(0,1,9,2,7,3),我們發現在[2,7]區間中有3個數被放入了左子樹,滿足k<=num,所以我們往左子樹中找,呼叫query(1,1,5,2,4,3)。

在第二層樹中我們發現區間[2,4]只有乙個數被放入左子樹,所以我們要找的數一定在右子樹中,呼叫query(2,4,5,4,5,2)。

在第三層樹中,我們發現區間[4,5]只有乙個數被放入左子樹,同理我們應該往右子樹找,呼叫query(3,5,5,5,5,1)。現在可以發現l==r,則我們可以確定已經找到了要找的數,則返回4即可,我們可知在區間[2,7

]上第3小的數為4。

基礎的劃分樹就到這裡,下面給出我的**:

#include #include #include #include #define maxn 100010

#define mid ((l+r)>>1)

using namespace std;

int t[20][maxn],sum[20][maxn];

int a[maxn],as[maxn];

//以下為查詢區間第k小劃分樹

void build(int p,int l,int r)

for(i=l;i<=r;i++)

else

t[p+1][rs++]=t[p][i];

}else if(t[p][i]下面是兩道劃分樹的模板題

poj 2104

題解這裡有

hdu 4417

題解這裡有:

資料結構 劃分樹小結

劃分樹是一種基於線段樹的資料結構。主要用於快速求出 在log n 的時間複雜度內 序列區間的第k大值。先看下圖已經建好的劃分樹是什麼樣子的,原始陣列是 1,5,2,3,6,4,7,3,0,0 並把它作為樹的第0層,然後把這些數中較小的數再組成 1,2,3,0,0 順序還是遵照原陣列的順序,同樣將較大...

整數劃分(小結劃分數如何dp)

原 小結劃分數如何dp 1.hdu 1028 整數劃分 首先,我們引進乙個小小概念來方便描述吧,dp n m 是把自然數劃劃分成所有元素不大於m的分法,例如 當n 4,m 1時,要求所有的元素都比m小,所以劃分法只有1種 當n 4,m 2時,只有3種,當n 4,m 3時,只有4種,當n 4,m 5時...

劃分樹詳解

題目 給出n個數,和m個區間 對於每個區間 l r 輸出這個區間裡面第k大的數。我們來看看劃分樹是怎麼構造的。構造 以2104為例子,舉2 0 6 8 5 1 4 3 9為例子,構造劃分樹是這樣的 上面的內容是用乙個二位陣列val儲存下來的,第一維表示劃分樹的第幾層,第二位表示在這一層中的位置。要注...