主席樹是可持久化的線段樹,其最大的優點就是在消耗記憶體較少的情況下保證了線段樹的結構。
那麼什麼是主席樹呢?對於區間[1,n],對於每乙個子區間[1,i]建立一棵線段樹(1<=i<=n),線段樹的每乙個節點存某個字首[1..i]中屬於區間[l..r]的數一共有多少個,這就是一顆主席樹。
如果我們對於每乙個區間都建一棵樹,那肯定會爆記憶體,但由於區間[1,i]和區間[1,i+1]間僅有乙個點的差別,所以線段樹i和i+1也只有很小的差別,大部分點可以共用。只要在前一棵樹上改動幾個點,就可以形成新的樹,這樣就節省了許多的空間。
求區間k小,這個問題是乙個經典的主席樹問題,我們先討論靜態區間(動態區間需要樹狀陣列套主席樹才行)。
我們先把序列離散,排序。然後只需要建立n顆線段樹就行,第i樹維護[1,i]序列,這樣我們處理任意區間l, r時就可以通過處理區間[1,l - 1], [1,r],就行,然後兩者的處理結果進行相加相減就行。主席樹的結果滿足加減的性質,因為樹l-1的點肯定也是樹r的點。
靜態區間k小**:
#include
#define maxn 200005
using namespace std;
intread()
struct edget[maxn*40];
struct nodef[maxn];
int n,m,cnt,rank[maxn],root[maxn];
int cmp(node a,node b)
void update(int p,int &x,int l,int r)
int query(int i,int j,int k,int l,int r)
int main()
; }
sort(f+1,f+1+n,cmp);
cnt=1;t[0]=(edge);root[0]=0;
for(int i=1;i<=n;i++) rank[f[i].pl]=i;
for(int i=1;i<=n;i++)
for(int i=1;i<=m;i++)
return
0;}
主席樹(可持久化線段樹)
我真弱。連主席樹都不會。主席樹相當於多個線段樹,由於相鄰兩棵線段樹的節點的值只有少許不同,因此可以對於和前一棵樹一樣的子樹乙個指標指過去,無需操作,這樣每棵樹o logn 總複雜度o nlogn 以下是區間k大 include include include define n 100005 defi...
主席樹 可持久化線段樹
首先要學會普通的線段樹,然後理解權值線段樹,而主席樹就是多個權值線段樹 我自己的理解 但是這多個權值線段樹之間有公共部分,節約了空間。它一開始是乙個空樹,後來逐個添數,記錄新增的這個數在那個範圍內,並 1,顯然它每次只更新了一條鏈,其他不需要變,這樣就有了多個版本的線段樹。如果求 l,r 範圍內第k...
可持久化線段樹(主席樹)
qwq我大概又是機房最後乙個學主席樹的了吧 其實之前一直都在講 只是沒做題 做了幾道以後發現都是乙個套路qwq關鍵就是能不能看出來要用主席樹 主要可以解決 靜態 動態區間第k大 樹上也可以 一些有關區間的帶某些限制的詢問 如出現次數等 先把模板粘上來 include include include ...