主席樹 可持久化線段樹

2021-09-25 15:42:06 字數 1924 閱讀 7782

主席樹,即可持久化線段樹

可持久化:可以找到每次修改時的線段樹,即儲存了線段樹各個歷史版本,這樣就可以快速查詢到第 i 次修改前線段樹的狀態。

核心思想與歷史版本的線段樹共用部分結點

很明顯每次新建一棵線段樹帶來的時空消耗是難以承受的,但是可以發現,每次單點修改時,只會變動logn個結點(即從根結點到對應葉結點的路徑),所以剩下的結點都可以和前乙個版本的線段樹共用。(所以要每次採用動態建立logn個結點,且可以發現每個版本的根結點一定不同

m次修改,空間複雜度為o( 4n + m*logn )(4n為初始版本線段樹大小)

建樹:即建立初始版本的線段樹,注意,即使一開始為空樹,也必須要建立(令值全為0),因為修改操作必須存在前乙個版本的樹

int root[maxn]

;//root[i]:第i個版本線段樹的根結點

int t[maxn<<5]

,ls[maxn<<5]

,rs[maxn<<5]

,cnt=0;

//結點,左子樹,右子樹,注意空間要開足夠大

intbuild

(int l,

int r)

int mid=

(l+r)

>>1;

ls[rt]

=build

(l,mid)

; rs[rt]

=build

(mid+

1,r)

; t[rt]

=t[ls[rt]

]+t[rs[rt]];

return rt;

} root[0]

=build(1

,n);

//建初始版本線段樹

修改:一定要存在前乙個版本的樹

int

updata

(int l,

int r,

int pos,

int val,

int pre)

ls[rt]

=ls[pre]

,rs[rt]

=rs[pre]

;//先繼承上乙個版本的左右子樹

int mid=

(l+r)

>>1;

if(pos<=mid)

ls[rt]

=updata

(l,mid,pos,val,ls[pre]);

//向左更新,pre也要變

else

rs[rt]

=updata

(mid+

1,r,pos,val,rs[pre]);

//向右更新,pre也要變

t[rt]

=t[ls[rt]

]+t[rs[rt]];

return rt;

} root[i]

=updata(1

,n,pos,val,root[i-1]

);//第i次修改

查詢:查詢操作並未改變,只是要限定某個版本

int

query

(int rt,

int l,

int r,

int ql,

int qr)

query

(root[i],1

,n,ql,qr)

;//詢問第i個版本的線段樹

主席樹(可持久化線段樹)

我真弱。連主席樹都不會。主席樹相當於多個線段樹,由於相鄰兩棵線段樹的節點的值只有少許不同,因此可以對於和前一棵樹一樣的子樹乙個指標指過去,無需操作,這樣每棵樹o logn 總複雜度o nlogn 以下是區間k大 include include include define n 100005 defi...

主席樹 可持久化線段樹

首先要學會普通的線段樹,然後理解權值線段樹,而主席樹就是多個權值線段樹 我自己的理解 但是這多個權值線段樹之間有公共部分,節約了空間。它一開始是乙個空樹,後來逐個添數,記錄新增的這個數在那個範圍內,並 1,顯然它每次只更新了一條鏈,其他不需要變,這樣就有了多個版本的線段樹。如果求 l,r 範圍內第k...

可持久化線段樹(主席樹)

qwq我大概又是機房最後乙個學主席樹的了吧 其實之前一直都在講 只是沒做題 做了幾道以後發現都是乙個套路qwq關鍵就是能不能看出來要用主席樹 主要可以解決 靜態 動態區間第k大 樹上也可以 一些有關區間的帶某些限制的詢問 如出現次數等 先把模板粘上來 include include include ...