主席樹(chairman tree)(據說是被chairman傳開的)
它是一種專門用來實現求區間第k大這類操作的資料結構
q:這不是分塊輕鬆解決的事嗎?
a:是的,但是分塊時間為
q:這是不是很難,**複雜度極高?
a:nonono,**複雜度一點都不高,前置知識只有動態開點線段樹
q:那我不會怎麼辦?
a:右**行度娘,或者菜雞的部落格
菜雞很菜,剛學了主席樹,還是最簡單的靜態
首先思考一下,區間求第k大,最暴力的解自然是每次排序,是
q:如果用資料結構維護呢?
a:每次詢問用一棵權值線段樹或者權值樹狀陣列+二分維護,也是,qaq,(不會可見可憐的狗狗這道題)
權值樹狀陣列+二分姑且不論,我們只談權值線段樹(時間複雜度低才是王道)
每次詢問的是一段區間,與區間相關的演算法沒有多少,也就字首和,線段樹……
權值線段樹下標記的是值的大小,存的是出現次數,所以具有可加減性
故選用字首和
前面的引導就差不多結束了,進入正文了
主席樹=字首和+線段樹=對每個字首和中的點開一棵權值線段樹(下標記的是權值的線段樹)
線段樹上的結點記錄
建立每次只用新插入乙個結點,
如果該結點應該在左子樹,右子樹就不用變;反之左子樹不用變
每次新插入只用
void add(int &p,int l,int r,int x)
//lc為左兒子,rc為右兒子,s為結點個數
查詢:由於上文提到線段樹具有可減性,只用在(不會可見可憐的狗狗這道題,也可以看**)
int kth(int p1,int p2,int l,int r,int x)
總結:主席樹就是字首和+線段樹的思想毒瘤了一點(有心人可以看出我上面的引導是倒推的),但是只要你熟練掌握線段樹,知道思想後小菜一碟
例題(時刻更新)
1、luogu p3834 【模板】可持久化線段樹 1(主席樹)
額,模板題,加個離散化就號了
#include#includeusing namespace std;
const int n=4e6+5;
int n,m,rt[n],b[n];
struct aa[n];
bool cmp(a x,a y)
int kth(int p1,int p2,int l,int r,int x)
}zxs;
int main()
return 0;
}
2、可憐的狗狗(這是超連結)
模板題*2
3、luogu p3919 【模板】可持久化陣列(可持久化線段樹/平衡樹)
模板題*3
4、bzoj 2223: [coci 2009]patuljci
模板題,查詢中位數相同的是否超過序列長度的一半
靜態主席樹
首先主席樹解決什麼樣的問題?最經典的問題就是 區間第k小問題 也就是指定乙個區間,要求求出這個區間中第k小的數字 在搞懂什麼是主席樹之前,我們要先對權值線段樹有一定的了解,下面我們就先說一下權值線段樹,然後詳細說一下主席樹以及主席樹程式的實現.權值線段樹 每個葉子節點的數值表示的是 陣列中含有這個數...
靜態主席樹
主席樹 對於序列的每乙個字首建一棵以序列裡的值為下標的線段樹 所以要先離散化 記錄該字首序列裡出現的值的次數 記離散後的標記為1 n 下面值直接用1 n代替 對於區間 x,y 的第k大的值,那麼從root x 1 root y 開始,t root y 1,mid root x 1 1,mid t表示...
主席樹 靜態 的輕鬆入門
n i 1 85 kj 0i2 i 1n 58 j 0ki2 emmm 最近入門了主席樹,感覺其實不是很難,主要理解了就很簡單了 畢竟 這麼短 給出乙個數列,求區間 l r 之間的第 k 大值利用數列中 n 個資料建立 n 棵樹,其中第 i 棵樹維護 1 i 這個字首內的資料資訊 第 i 棵樹中的每...