前言
要學可持久化並查集,必須先會可持久化陣列。
簡介l in
klink
link
可持久化陣列詳見部落格可持久化專題(二)——可持久化陣列的實現
可持久化並查集應該是乙個挺實用的資料結構(例如noi2018day1t1中就有它的身影)。
它主要建立於可持久化陣列的基礎之上(而可持久化陣列的實現是完全基於主席樹的),因為這樣就可以去訪問一些歷史版本從而實現可持久化了。
按秩合併l in
klink
link
主席樹詳見部落格可持久化專題(一)——**主席樹:可持久化線段樹
由於可持久化的緣故,我們要切記,可持久化並查集是不能像普通並查集一樣寫路徑壓縮的!
或許有人會問,不路徑壓縮,還不t
tt飛?
沒關係,沒有路徑壓縮,我們還有按秩合併,它的複雜度均攤是o(l
ogn)
o(logn)
o(logn
)的,平時由於已經有路徑壓縮了,
所以基本上沒人寫按秩合併(實在沒什麼必要,時間複雜度優化並不大),而此時此刻,沒法用路徑壓縮,按秩合併就起了很大的作用。
具體實現l in
klink
link
按秩合併的複雜度證明詳見部落格啟發式合併
如果對可持久化並查集還有什麼不懂的,最好再多思考一下,畢竟這還是有點深奧的。
下面是洛谷上可持久化並查集板子題的**:(**比可持久化陣列長了許多)
#include
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define ll long long
#define swap(x,y) (x^y?(x^=y,y^=x,x^=y):0)
#define tc() (a==b&&(b=(a=ff)+fread(ff,1,100000,stdin),a==b)?eof:*a++)
#define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
#define n 200000
int pp_=0;
char ff[
100000],
*a=ff,
*b=ff,pp[
100000];
using
namespace std;
int n,q,tot=
0,rt[n+5]
,a[n+5]
;struct chairman_tree
node[n*20]
;inline
void
read
(int
&x)inline
void
write
(int x)
inline
void
build
(int
&rt,
int l,
int r)
//初始的建樹,一開始每個節點的fa都是本身,這是並查集的基礎思想
build
(node[rt]
.son[0]
,l,mid)
,build
(node[rt]
.son[1]
,mid+
1,r);}
inline
void
newpoint
(int
&rt,
int lst,
int l,
int r,
int x,
int fa)
//新插入乙個節點
//更新fa,並複製以前版本的這個節點的level
node[rt]
.son[0]
=node[lst]
.son[0]
,node[rt]
.son[1]
=node[lst]
.son[1]
;if(x<=mid)
newpoint
(node[rt]
.son[0]
,node[lst]
.son[0]
,l,mid,x,fa)
;else
newpoint
(node[rt]
.son[1]
,node[lst]
.son[1]
,mid+
1,r,x,fa);}
inline
void
add_level
(int rt,
int l,
int r,
int x)
//增加乙個節點的在按秩合併時的優先順序
if(x<=mid)
add_level
(node[rt]
.son[0]
,l,mid,x)
;else
add_level
(node[rt]
.son[1]
,mid+
1,r,x);}
inline
intquery
(int rt,
int l,
int r,
int x)
//詢問x節點在某一版本下的位置
inline
intgetfa
(int rt,
int x)
//詢問x節點在某一版本下的祖先
inline
void
connect
(int v,
int x,
int y)
//在版本v中連線x和y,將他們放入乙個集合中
intmain()
}return
fwrite
(pp,
1,pp_,
stdout),
0;}
可持久化陣列與可持久化並查集
可持久化陣列 維護這樣的乙個長度為 n 的陣列,支援如下幾種操作 在某個歷史版本上修改某乙個位置上的值 訪問某個歷史版本上的某一位置的值 此外,每進行一次操作 對於操作2,即為生成乙個完全一樣的版本,不作任何改動 就會生成乙個新的版本。版本編號即為當前操作的編號 從1開始編號,版本0表示初始狀態陣列...
可持久化並查集
n個集合 m個操作 1 a b 合併a,b所在集合 2 k 回到第k次操作之後的狀態 查詢算作操作 3 a b 詢問a,b是否屬於同一集合,是則輸出1否則輸出0 所給的a,b,k均經過加密,加密方法為x x xor lastans,lastans是上一次的輸出答案 並查集實質是乙個陣列,可持久化並查...
可持久化並查集
可持久化陣列 可持久化陣列是一種可以回退,訪問之前版本的陣列 是一些其他可持久化資料結構的基石 例如可持久化並查集 與普通並查集不同的是 這裡用到了 按秩合併新增鏈結描述 include const int n 2e5 7 int rootfa n rootdep n cnt,tot struct ...