n個集合 m個操作
操作:
1 a b 合併a,b所在集合
2 k 回到第k次操作之後的狀態(查詢算作操作)
3 a b 詢問a,b是否屬於同一集合,是則輸出1否則輸出0
可持久化並查集模板題
//並查集實質是乙個陣列,可持久化並查集就是乙個可持久化陣列,可以用可持久化線段樹維護,本質就是這樣
//只有葉子節點維護資訊,其他節點都是空
#include
using
namespace
std;
const
int n = 20000 + 10, m = 500000 + 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 ufs_find(int p, int x) //找到p所在集合的公共祖先,非遞迴版
return r;
}//int ufs_find(int p, int x) //找到p所在集合的公共祖先,遞迴版
////int ufs_find(int p, int x) //找到p所在集合的公共祖先,遞迴版並壓縮路徑
//int main()
else
if(op == 2)
else
}return
0;}
bzoj3673 可持久化並查集
bzoj 我們考慮把每個操作建成乙個點 i 對於 1 和 3 操作,連邊 i 1,i 對於 2 操作,連邊 k i,i 容易發現這是一棵樹,並且並查集的操作可以回退,那麼我們直接在樹上dfs,在進入節點 回溯時處理merge split 查詢即可.時間複雜度 o m log n 超短.pragma ...
BZOJ3673 可持久並查集
可以用線段樹維護 每個葉子結點存它父親的位置 查乙個點的父親和正常並查集差不多 記錄每個點的深度 當要相連的兩個點深度相同時 p,q 把q的deep 整體用主席樹維護 copy hzwer的 orz include include using namespace std inline int rea...
BZOJ 3673 可持久化並查集 by zky
n個集合 m個操作 操作 1 a b 合併a,b所在集合 2 k 回到第k次操作之後的狀態 查詢算作操作 3 a b 詢問a,b是否屬於同一集合,是則輸出1否則輸出0 05 6 1 1 2 3 1 2 2 0 3 1 2 2 1 3 1 2 1 0 1可持久化並查集不好寫,我們考慮到並查集的寫法就是...