pku2104 第k大數 劃分樹做法

2021-05-27 07:33:29 字數 1028 閱讀 4005

題意:求任意區間第k大數

劃分樹相容了快排和歸併的特點。。。採用劃分的思想逐漸往下劃,最後葉子節點的元素就是排好序的元素。。。其實可以理解成穩定的快排。。。和歸併樹一樣,記錄每一層的結果。。。並記錄toleft。。。

查詢的過程,總是查詢[ tt[p].l [ l, r] tt[p].r ]。。。這裡就有了幾個區間,想想,劃分樹劃分下去的時候[tt[p].l, l-1]中不大於中位數的一定靠在最前,[l, r]中不大於中位數的排在其後。。。我們通過計算[l, r]中不大於中位數的個數l2來和k比較,來確定是到左子樹還是右子樹去找,查詢的範圍都可以通過兩個區間劃分到左子樹的個數來縮小。。。。

時間複雜度nlgn+mlgn,比歸併樹nlgn+m(lgn)^3快多了,m越大效果越好。。

**:比歸併樹快一倍吧。。。

#include #include #include #include using namespace std;

const int n=100010;

const int deep=20;

int n, m, sa[n];

int seq[deep][n]; //歸併樹

int toleft[deep][n]; //記錄當前層左邊界到i位置有多少劃入左子樹

struct node

tt[n*4];

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

else

else

}} build(l, tt[p].mid, d+1, p*2);

build(tt[p].mid+1, r, d+1, p*2+1);

}int query(int l, int r, int k, int d, int p)

else

int ll, rr;

if(k<=l2)

else }

int main()

{ int i, j, x, y, k;

while(scanf("%d%d", &n, &m)!=eof)

{ for(i=0; i

劃分樹 求區間K大數

求區間k大數,眾所周知有二分答案 樹套樹的做法,每個詢問複雜度為o log3n 可謂近似乙個o n 了,不僅時間複雜度高,程式設計複雜度也不低,後來才發現還有一種叫劃分樹的資料結構,專門做這種問題。本來覺得知道個樹套樹就夠了,據我所知劃分樹還不支援區間修改操作,但是這次noi一試的piano偏偏那出...

poj2104 主席樹區間第k大

主席樹裸題,過了好久都快忘了。主席樹主要就是使多個線段樹並行於一顆樹中,儲存的是一段區間內數字出現的個數,所以先離散化。數字的更改只影響了一條從這個葉子節點到根的路徑,所以只有這條路徑是新的,其他的都沒有改變。比如對於某個節點,要往右邊走,那麼左邊那些就不用新建,只要用個指標鏈到原樹的此節點左邊就可...

poj 2104 主席樹 靜態區間第k大

主席樹入門題目,主席樹其實就是可持久化權值線段樹,rt i 維護了前i個數中第i大 小 的數出現次數的資訊,通過查詢兩棵樹的差即可得到第k大 小 元素。include include include using namespace std define lson i node i lson defi...