主席樹 學習筆記

2021-10-03 15:40:38 字數 2002 閱讀 8657

主席樹就是權值線段樹的乙個集合;

模板題為求某個區間的第 k 大,權值線段樹也有求第 k 大這個功能,但是不能維護區間,只能求整個全域性第 k 大;

所以學習這個之前,務必先搞懂權值線段樹;

所以**都是這道題的;

【模板】可持久化線段樹 1(主席樹)

1、先從建樹開始說起:

int

build

(int l,

int r)

return rt;

}

這個建樹和線段樹是不一樣的,我沒有用結構體建樹,因為我認為線段樹用結構體建樹,結構體裡面的 l,r 是區間邊界,而主席樹是左兒子和右兒子,會搞混,所以直接用l,r;

這個建樹沒有利用二叉樹的性質(當父節點是k,左兒子是2* k 右兒子是2*k+1);而是直接先序遍歷,記錄乙個節點的左右兒子結點;這樣建樹的好處在於方便後面加鏈;

2、更新操作

int

update

(int pre,

int l,

int r,

int pos)

return rt;

}

個人認為,更新操作就是主席樹的精髓所在,每次插入乙個值,相當於又建一顆權值線段樹,但是這個又建並不是又開陣列重新建乙個,而是在原先的基礎上再加一條鏈,這個不好理解,建議配合和**理解;

3、查詢操作

int

query

(int pre,

int nw,

int l,

int r,

int k)

這個就是權值線段樹的思想了,當左子樹的值大於 k 時,說明左子樹一定存在解,反之,遍歷右子樹;

但是這裡最關鍵的是左子樹的值怎麼獲取,主席樹就體現出來了;

總的**:

#include

#define ll long long

#define pa pair

#define ls k<<1

#define rs k<<1|1

#define inf 0x3f3f3f3f

using

namespace std;

const

int n=

200100

;const

int m=

10000000

;const ll mod=

100000000

;int n,m,a[n]

,b[n]

,c[n]

,ans[n]

,tr[n]

,l[n*40]

,r[n*40]

,sum[n*40]

,root;

intbuild

(int l,

int r)

return rt;

}int

update

(int pre,

int l,

int r,

int pos)

return rt;

}int

query

(int pre,

int nw,

int l,

int r,

int k)

intmain()

sort

(a+1

,a+n+1)

;int cnt=

unique

(a+1

,a+n+1)

-a-1

;for

(int i=

1;i<=n;i++

) tr[0]

=build(1

,cnt)

;for

(int i=

1;i<=n;i++

)while

(m--

)return0;

}

主席樹學習筆記

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

主席樹學習筆記

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

主席樹 學習筆記

對於詢問 1,n 的第 k 小數,我們都知道直接上權值線段樹就行了。那麼對於任意區間的第 k 小數呢?暴力一點,每次開一顆線段樹。空間肯定 那麼此時,主席樹便應運而生。主席樹的主要思想就是 保留每次插入操作時的歷史版本,以便查詢區間第 k 小的數。先說流程。1.先建一顆空的權值線段樹,1,len 2...