主席樹
周五晚蔡大神講了下,覺得不是很難的東西,然後就可是敲,發現好像就是個持久化線段樹(?!)
當晚筆記:
主席樹,其實就是多棵可持久化權值線段樹
那什麼是可持久化線段樹呢?
如樹1中就在子樹i,樹2中也存在長的一毛一樣的子樹i』,那麼我們完全不用建兩棵相同的子樹啊,直接樹1子節點是i,樹2的子節點也是i……(這樣還是樹麼orz)
何為主席樹,
比如數列【2,3,1,6,4,5】
那麼權值為【1-6】
然後一樹以包括建一棵權值線段樹
二樹以包括【2,3】建一棵權值線段樹
三樹以包括【2,3,1】建一棵權值線段樹
六樹以包括【2,3,1,6,4,5】建一棵權值線段樹。
可以發現要建好多棵線段樹,還可以發現樹i是在樹i-1的基礎上建的。(這用於以後的修改,先不說)
然後我們來研究下這些樹的性質:
比如在統計【l,r】中大於y的點有多少個。
發現樹r的資訊減掉樹l-1的資訊,然後就可以得到【l,r】的資訊(也可以看成一棵【l,r】的權值線段樹)
至於修改,前面說了,只是在前乙個基礎上改罷了
修改操作:簡單說就是左樹不一樣那麼就左樹改右樹還是老樹……
procedure insert(x,ll,rr,old:longint;varview codenew:longint);
varmid:longint;
begin
inc(tot);
new:=tot;
sum[new]:=sum[old]+1;
if ll=rr then
exit;
mid:=(ll+rr)>>1;
if x<=mid then
begin
right[new]:=right[old];
insert(x,ll,mid,left[old],left[new]);
endelse
begin
left[new]:=left[old];
insert(x,mid+1
,rr,right[old],right[new]);
end;end;
要是碰到修改怎麼辦……
如果從左到右重建,就要修改好多棵線段樹。但是發現樹i儲存的是【1,i】的資訊,這東西不就是資訊的字首和?字首和在單點修改時有個神器bit,使修改n詢問1變為修改logn詢問logn。
單點修改
procedureview codeadd(x,y,z:longint);
begin
while x<=n do
begin
change(y,z,
1,total,root[x],root[x]);
inc(x,lowbit(x));
end;end;
把insert稍微改裝一下變成change,多了個引數y,當是刪除時y=-1,加是y=1.(其實就是bit套主席樹而已啦)
然後區間的還沒寫過。
然後主席樹各種速度碾壓好可怕。
然後我的主席樹好像寫的很醜?
最後是題目彙總:
1901: zju2112 dynamic rankings
3524: [poi2014]couriers
3207: 花神的嘲諷計畫ⅰ
2653: middle
3439: kpm的mc密碼(略歡樂,倒建trie似乎在usaco就見過,還有出題人提供的題解有很強的誤導向,他是專門寫複雜來嚇我們的!然後小問題調了好久)
主席樹 初學
現在才開始學主席樹 弱 不過不帶修改的話 還是很簡單的嘛。或者說應該叫可持久化線段樹?首先對數的區間進行離散化,這樣下面的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...