BZOJ 3637 可持久化並查集 by zky

2021-08-09 02:17:07 字數 1441 閱讀 2056

題意:n個集合 m個操作

操作:1 a b 合併a,b所在集合

2 k 回到第k次操作之後的狀態(查詢算作操作)

3 a b 詢問a,b是否屬於同一集合,是則輸出1否則輸出00

思路:裸的可持久化並查集。

我們知道普通的並查集就是乙個pre陣列,現在需要可持久化,維護歷史版本的pre陣列。和主席樹是有相通之處的,

都是每個節點維護了一棵線段樹,然後每次修改只會修改到一條鏈,這道題也是一樣的。

可持久化線段樹維護可持久化陣列從而維護可持久化並查集.

可持久化線段樹里維護的是並查集中的資訊。乙個pre,乙個啟發式合併的size(因為不能壓縮路徑,所以要降低查詢 根

的複雜度,讓子樹深度盡量平衡,要注意下如果兩個深度相同的合併,深度需要+1, 不同的話合併後的深度就是

深度大的

那個)。

並查集的find操作就從可持久化線段樹里找。

**:

#include#include#include#includeusing namespace std;

typedef long long ll;

const int maxn = 2e4*20;

int t[maxn], pre[maxn], deep[maxn], lson[maxn], rson[maxn];

int cnt, n, m;

int build(int l, int r)

return rt;

}int query(int root, int l, int r, int pos)

int find(int root, int x)

void update(int root, int l, int r, int pos)

int mid = (l+r)/2;

if(pos <= mid) update(lson[root], l, mid, pos);

else update(rson[root], mid+1, r, pos);

}int modify(int pre, int l, int r, int pos, int val)

lson[rt] = lson[pre], rson[rt] = rson[pre];

int mid = (l+r)/2;

if(pos <= mid) lson[rt] = modify(lson[pre], l, mid, pos, val);

else rson[rt] = modify(rson[pre], mid+1, r, pos, val);

return rt;

}void union_set(int fa, int fb, int i)

int main(void)

else if(cmd == 2)

else}}

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

可持久化並查集

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