主席樹就是權值線段樹的乙個集合;
模板題為求某個區間的第 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...