主席樹 學習筆記

2022-05-31 03:54:11 字數 2188 閱讀 6266

主席樹——可持久化線段樹。話說這個名字的來歷也非常有意思,傳說是一位非常非常巨的巨佬考場上現場yy出來了這種資料結構,他的名字叫做黃嘉泰(hjt)。於是就叫主席樹了……

所謂可持久化線段樹,就是可以查詢歷史更新資訊的線段樹。例如對線段樹進行了5次更新,但是需要查詢第2次更新結束後的結果……一種顯而易見的做法是每次更新重新建樹。但是這樣的空間不知爆到**去了……

其實主席樹的做法也是比較天然的。考慮一次單點更新只會對線段樹的一串節點(\(logn\)個)做出修改,剩下的節點依然沒有改變。因此考慮每一次新增一批節點,使這批節點依附在原始的線段樹上。

在普通的線段樹中,我們按照規則:左子樹的編號為父親2,右子樹編號為父親2+1. 然而這個規則在主席樹里就不再適用了,因為為了充分利用空間,乙個兒子可能對應多個父親。因此我們需要專門記錄每個節點的左右兒子編號

第\(i\)次更新後的線段樹的根節點編號。記為\(t[i]\)。顯然只要知道某一根節點編號,就能夠一步一步找到其對應的線段樹。乙個根節點對應乙個狀態的線段樹,不同的狀態的線段樹可能有公共節點。因此在今後查詢某一狀態的線段樹時,只要找到這個\(t[i]\)就好了。

在**實現上,我們先假設其左右兒子不做更改,然後再乙個乙個改變下去。

int update(int pre, int l, int r, int x)

return cur;//這裡包括l==r的情況

}

注意這裡的\(update\)函式是有返回值的,返回更新成功後新的那乙個新節點的編號。

傳送門:>here

<

採用可持久化權值線段樹。

權值線段樹查詢總體第\(k\)小並不難,和平衡樹查詢第\(k\)小非常相似。先離散化,然後利用權值線段樹維護每個區間(葉子當然是從小到大的權值了)的數字個數。查詢時只需要從根節點往下走,每次比較其左兒子出現個數是否大於或等於\(k\)。如果左兒子中的數字個數都已經\(\geq k\)了,往左兒子走即可。否則就往右兒子走,記得此時應當繼續查詢第\(k-sum[lson]\)

注意,權值線段樹中葉子節點\([x,x]\)的值即代表數字\(x\)出現的次數。於是主席樹中的某個節點的值代表當前狀態下某個區間內數字出現次數的總和

好了,現在考慮如何查詢區間。我們發現要求第\(k\)大,實際上就是要求出每個區間內數字的個數。即區間\([l,r]\)內某個數的出現次數,等於\([1,r]\)內的出現次數減去\([1,l-1]\)內的出現次數。因此在主席樹上看來就是兩個對應狀態的線段樹某個節點的值相減。相減之後我們就得到了這段區間內每個數的出現次數。然後就利用剛才的方法查詢第\(k\)大就可以了

/*by dennyqi 2018*/

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

typedef long long ll;

const int maxn = 100010;

const int inf = 1061109567;

inline int max(const int a, const int b)

inline int min(const int a, const int b)

inline int read()

struct numa[maxn];

int n,m,z,y,x;

int t[maxn],mp[maxn];

struct zxs

return cur;

}int query(int pre, int u, int l, int r, int k)

}hjt;

inline bool cmp1(const num& a, const num& b)

inline bool cmp2(const num& a, const num& b)

int main()

sort(a+1, a+n+1, cmp1);

for(int i = 1; i <= n; ++i)

sort(a+1, a+n+1, cmp2);

for(int i = 1; i <= n; ++i)

for(int i = 1; i <= m; ++i)

return 0;

}

[ 應用 1 ]: >題解:洛谷p2633 \(count \ on \ a \ tree\)

<

剩餘部分待更…………………………

主席樹學習筆記

問題 給定乙個n個數的序列,q次詢問第x個數到第y個數中的第k最值。我們假定是第k小。為了使討論更加簡便,我們假定序列的每個數都是不大於n的正整數。當然一般題目中元素範圍很大,但是可以用離散化預處理來做到這一點。考慮乙個比較高階的做法 令g i j 為前i個數中,值為j的數的個數。很容易用o n 2...

主席樹 學習筆記

主席樹就是權值線段樹的乙個集合 模板題為求某個區間的第 k 大,權值線段樹也有求第 k 大這個功能,但是不能維護區間,只能求整個全域性第 k 大 所以學習這個之前,務必先搞懂權值線段樹 所以 都是這道題的 模板 可持久化線段樹 1 主席樹 1 先從建樹開始說起 int build int l,int...

主席樹學習筆記

學習博文 主席樹總結 p3834 模板 可持久化線段樹 2 主席樹 給出乙個序列,每次詢問給定區間內第k小的值。主席樹模板。考慮最簡單的情況,也就是查詢區間固定。首先對資料進行離散化,用線段樹維護。每個節點對應離散化後值域的數的總個數 size.從上到下進行查詢時,判斷當前節點左子樹的 size 和...