主席樹即可持久化線段樹,也叫作函式式線段樹
至於為什麼叫做主席樹,據說是乙個叫hjt的神犇在考場上現場yy出來的
可持久化線段樹:
顧名思義就是線段樹經過了若干次修改之後,仍然能找到原來某次修改前的線段樹的資訊的一種資料結構
最暴力的方法就是,每次修改就複製當前的線段樹新建下一版本的一棵樹,在上面修改
空間複雜度\(o(mnlogn)\),時間複雜度\(o(mnlogn)\)
這樣並不高效,還不如不用
記得要用動態開點線段樹
單點修改模板題luogu3919
區間修改模板題spoj/vjudge
luogu靜態區間第k小模板題
給定\(n\)個正整數構成的序列,\(m\)組詢問,對於指定的閉區間查詢其區間內的第\(k\)小值
\(n,m<=2*10^5\)
這道題的做法:
類似把數字離散化,主席樹為值域線段樹,維護數的個數
從第乙個數字開始不停的往主席樹中加點,每加乙個數字,就新建乙個版本
那麼第\(i\)棵線段樹儲存的就是前\(i\)個數字
查詢區間\([l,r]\)第\(k\)小?
和全域性第\(k\)小的做法一致,但是我們要找的只是陣列\([l,r]\)中的數
之前說過第\(i\)棵線段樹儲存的就是前\(i\)個數字
那麼運用字首和的方法,把第\(r\)棵線段樹和第\(l-1\)棵線段樹作差,得到的就是這個區間內的數,其它的都和全域性第\(k\)小沒有區別
此時樹就像是乙個二維平面
橫縱座標分別為樹的版本和每一棵樹
提一下:如果要做動態的區間第\(k\)小,即帶修改,要用到樹狀陣列套線段樹來做,思路很相似,就是把陣列區間那一維用樹狀陣列來維護
bzoj2588count on a tree
一棵\(n\)個節點的樹,每個點有乙個權值,對於\(m\)個詢問\((u,v,k)\),你需要回答\(u\)和\(v\)這兩個節點間第\(k\)小的點權
\(n,m<=100000\)
做法
主席樹還是為值域線段樹,維護數的個數
每個點的線段樹版本由它的父親加入它的點權得到
那麼每個點的線段樹存的就是它到根的所有點的點權
還是樹上二分數字,還是線段樹作差:
假設\(u, v\)的lca為\(x\),用\(rt[i]\)表示\(i\)這個點的線段樹
那麼就是這樣作差
\(rt[u]+rt[v]-rt[x]-rt[fa[x]]\)
這樣就只包含了\(u,v\)路徑上所有的點了
hdu4251
給定\(n\)個正整數構成的序列\(a\),將對於指定的閉區間查詢其區間內的中位數的值
\(n,m<=100000,a[i] \in [1, 10^9]\)
做法
\(emmm...\)
這不就是區間第長度除以\(2\)小嗎?
spoj3267
給定\(n\)個正整數構成的序列\(a\),\(q\)組詢問,於指定的閉區間查詢其區間內的不同的數的個數
\(n,q<=30000,a[i]\in[1, 10^6]\)
做法
不是權值線段樹
維護位置
如果插入乙個數時發現之前有過了
那麼修改當前的,那個位置\(−1\)
然後插入這個數字,在相應的位置\(+1\)
詢問\([l,r]\)就是第\(r\)棵線段樹中\([l,r]\)的區間和
好像沒有找到題誒。。。
給定\(n\)個正整數構成的序列,將對於指定的閉區間查詢其區間內前\(k\)小的數的和
\(n,m<=100000\)
做法
先求第\(k\)小,答案就是它和它子樹的點的值的和
也就是主席樹再存下每個點離散化的值,維護值的和就好了
主要是沒什麼了,而且其它的基本上方法差不多
主席樹 初學
現在才開始學主席樹 弱 不過不帶修改的話 還是很簡單的嘛。或者說應該叫可持久化線段樹?首先對數的區間進行離散化,這樣下面的a i 都預設為離散化以後的結果了。對於每個1.i開乙個線段樹,對於這個線段樹中的每乙個節點 l,r 表示1.i中在 l,r 中的數的個數。顯然這n個線段樹的形態大小是完全一樣的...
主席樹 模板
思想 主席樹就是一顆持久化線段樹,為什麼叫持久化了,因為它可以儲存之前的線段樹版本,並且可以拿來用,從而優化空間.至於為什麼叫主席樹了,大概是因為發明這個演算法的人的名字的緣故吧 詳細說說 主席樹是一種離線資料結構,是由很多棵線段樹組成的。第i棵線段樹存的是前i個數的資訊 每乙個線段存數字的出現次數...
主席樹模板
維護n棵1 i的字首權值線段樹,每次查詢減一下就好了。poj 2104就是模板題,裸的靜態第k大,需要先離散化,不會的就用lower bound 多試試,研究研究應該就能懂。include include include include using namespace std const int m...