題意: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 ...