以前的空間 主席樹

2022-02-06 16:59:14 字數 1798 閱讀 1626

主席樹

周五晚蔡大神講了下,覺得不是很難的東西,然後就可是敲,發現好像就是個持久化線段樹(?!)

當晚筆記:

主席樹,其實就是多棵可持久化權值線段樹

那什麼是可持久化線段樹呢?

如樹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;var

new: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;

view code

要是碰到修改怎麼辦……

如果從左到右重建,就要修改好多棵線段樹。但是發現樹i儲存的是【1,i】的資訊,這東西不就是資訊的字首和?字首和在單點修改時有個神器bit,使修改n詢問1變為修改logn詢問logn。

單點修改

procedure

add(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;

view code

把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...