事實上是並查集套乙個可持久化陣列。
int a[100005];
struct segmenttree
void pushup(int o)
int buildhelp(int l, int r)
int m = (l + r) >> 1;
ls = buildhelp(l, m);
rs = buildhelp(m + 1, r);
pushup(o);
return o;
}int addhelp(int o, int l, int r, int p, ll v)
int m = (l + r) >> 1;
if(p <= m)
ls = addhelp(ls, l, m, p, v);
if(p >= m + 1)
rs = addhelp(rs, m + 1, r, p, v);
pushup(o);
return o;
}int sethelp(int o, int l, int r, int p, ll v)
int m = (l + r) >> 1;
if(p <= m)
ls = sethelp(ls, l, m, p, v);
if(p >= m + 1)
rs = sethelp(rs, m + 1, r, p, v);
pushup(o);
return o;
}int sumhelp(int o, int l, int r, int ql, int qr)
void build(int _n)
void add(int id, int pos, int val)
void set(int id, int pos, int val)
int sum(int id, int lpos, int rpos)
};struct disjointset
int find(int id, int x)
int size(int id, int x)
int merge(int id, int x, int y)
int sx = size.sum(ver[id], x, x);
int sy = size.sum(ver[id], y, y);
if(sx < sy)
find.set(ver[id], y, x);
size.add(ver[id], x, sy);
ver[++cur] = find.cur;
return x;
}} ds;
這裡預設merge操作產生乙個新的版本。並查集的ver[u]表示並查集的版本u對應線段樹的版本ver[u]
也就是說,並查集的ver[u]對應的線段樹根為find.ver[ver[u]],這裡find和size的樹根始終處於同一版本號,同步變化。
注意分清楚哪些操作產生新的版本。
假如是驗證中的例題,跳轉操作也產生新的版本,其他操作都在並查集的最後乙個版本上修改(和可持久化陣列的每個修改都帶old版本不同)。
注意並查集的最後乙個版本不見得對應線段樹的最後乙個版本,因為這裡為了節省空間使得線段樹並不會因為sum操作產生版本。
可持久化並查集
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 ...