主席樹 學習筆記

2022-03-26 10:28:02 字數 1116 閱讀 5619

對於詢問$[1,n]$的第$k$小數,我們都知道直接上權值線段樹就行了。那麼對於任意區間的第$k$小數呢?

暴力一點,每次開一顆線段樹。空間肯定**。那麼此時,主席樹便應運而生。

主席樹的主要思想就是:保留每次插入操作時的歷史版本,以便查詢區間第$k$小的數。先說流程。

1.先建一顆空的權值線段樹,$[1,len]$。

2.從$1$到$n$對於每個結點都新建一顆權值線段樹,$i$結點的線段樹根據$i-1$的更新,即在原基礎上進行加的操作。

3.若查詢$[l,r]$則拿出第$l-1$顆和第$r$顆線段樹進行比較,他們之間的差值就是$[l,r]$區間的元素個數。查詢第$k$小,就看左兒子的大小$x$。如果$k\leq x$,那麼答案肯定在左兒子,反之則在右兒子。注意此時$k$要更新成$k-x$,因為在右兒子的區間裡相對大小會發生變化。

主席樹有著滿足字首和和樹上差分等優秀性質(感性理解),所以不管是樹還是序列都可以維護。

注意:使用主席樹時請不要吝嗇你的空間,不然會出現奇奇怪怪的錯誤。一般來說我都開$n\log n$,實際上開$8*10^6$都可以。

**:

#include#define int long long

using

namespace

std;

const

int maxn=5000005

;int

n,m,len,a[maxn],b[maxn],sum[maxn],ls[maxn],rs[maxn],tot,rt[maxn];

inline

intread()

while(isdigit(ch))

return x*f;

}inline

int getpos(int x)

inline

int build(int l,int

r)inline

int update(int k,int l,int r,int

root)

return

dir;

}inline

int query(int u,int v,int l,int r,int

k)signed main()

return0;

}

主席樹學習筆記

問題 給定乙個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 和...