可持久化並查集

2021-08-08 20:27:23 字數 1917 閱讀 1224

//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是上一次的輸出答案

//並查集實質是乙個陣列,可持久化並查集就是乙個可持久化陣列,可以用可持久化線段樹維護,本質就是這樣

//只有葉子節點維護資訊,其他節點都是空

const int n = 200000 + 10, m = 5000000 + 10, inf = 0x3f3f3f3f;

int root[n], lson[m], rson[m], par[m], rnk[m];

int tot;

int n;

void build(int l, int r, int &x)//建樹,並初始化並查集

int mid = (l + r) >> 1;

build(l, mid, lson[x]);

build(mid + 1, r, rson[x]);

}int query(int l, int r, int p, int

x)//查詢p在當前版本下在樹中的編號

void update(int l, int r, int

pos, int val, int pre, int &x)//把pos的祖先更新為val

int mid = (l + r) >> 1;

if(pos

<= mid) update(l, mid, pos, val, lson[pre], lson[x]);

else update(mid + 1, r, pos, val, rson[pre], rson[x]);

}void add_rnk(int l, int r, int

pos, int

x)//增加pos的秩

int mid = (l + r) >> 1;

if(pos

<= mid) add_rnk(l, mid, pos, lson[x]);

else add_rnk(mid + 1, r, pos, rson[x]);

}int find(int p, int

x)//找到p所在集合的公共祖先,非遞迴版

return r;

}//int find(int p, int

x)//找到p所在集合的公共祖先,遞迴版

////int find(int p, int

x)//找到p所在集合的公共祖先,遞迴版並壓縮路徑

//int main()

else

if(op == 2)

else

}return

0;}

用rope實現的,比手寫的慢大概2~3倍:

//貼個rope版的,實現超級簡單

#include

#include

using

namespace

std;

using

namespace __gnu_cxx;

const

int n = 200000 + 10;

rope *par[n];

int a[n];

int find(int x, int cur)

void unite(int x, int y, int cur)

bool same(int x, int y, int cur)

int main()

else

if(opt == 2)

else

if(opt == 3)

}return

0;}

可持久化並查集

可持久化陣列 可持久化陣列是一種可以回退,訪問之前版本的陣列 是一些其他可持久化資料結構的基石 例如可持久化並查集 與普通並查集不同的是 這裡用到了 按秩合併新增鏈結描述 include const int n 2e5 7 int rootfa n rootdep n cnt,tot struct ...

可持久化並查集

點此看題 並查集最重要的就是fafa fa陣列,我們可以拿主席樹來維護這個fafa fa,並且每次改點只需要改乙個,為保證時間複雜度我們再維護乙個dep depde p來做啟發式合併,這就變成了乙個單點修改,單點查詢的主席樹了。include include using namespace std ...

可持久化並查集

可持久化資料結構是在原資料結構的基礎上增加維護歷史版本的功能。但可持久化並查集的具體思路是利用主席樹維護不同版本的每個節點的父節點.如果並查集結構是鏈式,用按秩合併會導致單次查詢複雜度為 n log n 於是我們可以啟發式合併,將最大深度較小的集合合併到較大的那乙個.剩下的,暴力查詢暴力合併即可.由...