n個集合 m個操作
1 a b 合併a,b所在集合
2 k 回到第k次操作之後的狀態(查詢算作操作)
3 a b 詢問a,b是否屬於同一集合,是則輸出1否則輸出0
5 6
1 1 2
3 1 2
2 03 1 2
2 13 1 210
1\(1 \le n \le 10^5, 1 \le m \le 2 \times 10^5\)
by zky 出題人大神犇
可持久化線段樹維護fa和rank/size
按秩合併/啟發式合併
#include #include #include #include #include #include #include inline int max(int a, int b)
inline int min(int a, int b)
inline void swap(int &x, int &y)
inline void read(int &x)
const int inf = 0x3f3f3f3f;
const int maxn = 400000 + 10;
struct node
node[maxn * 40];
int tot, n, m, fa[maxn], now, pos[maxn], cnt;
void build(int &o, int l = 1, int r = n)
int mid = (l + r) >> 1;
build(node[o].ls, l, mid);
build(node[o].rs, mid + 1, r);
}void insert(int &o, int oo, int p, int k, int l = 1, int r = n)
int mid = (l + r) >> 1;
if(p <= mid) insert(node[o].ls, node[oo].ls, p, k, l, mid), node[o].rs = node[oo].rs;
else insert(node[o].rs, node[oo].rs, p, k, mid + 1, r), node[o].ls = node[oo].ls;
}void add(int o, int p, int l = 1, int r = n)
int mid = (l + r) >> 1;
if(p <= mid) add(node[o].ls, p, l, mid);
else add(node[o].rs, p, mid + 1, r);
}int ask_f(int o, int p, int l = 1, int r = n)
int ask_rank(int o, int p, int l = 1, int r = n)
int find(int k, int x)
}void merge(int k, int x, int y)
int main()
else if(tmp1 == 2)
else
}return 0;
}
洛谷 P3402 可持久化並查集
解題思路 可持久化並查集也就是可持續化線段樹 並查集 主席樹 並查集 像我們平常做的並查集都是路徑壓縮,但因為要保證可持續化,所以資訊不能改變,所以我們採用啟發式合併來合併集合。啟發式合併的樹最高深度不會超過log n 1。因為深度為2的樹需要兩個點,那麼深度為3的需要兩個深度為2的也就是2 2 4...
P3402 模板 可持久化並查集
其實看看 自己就可以懂。注意 1.並查集不壓縮路徑,壓縮了就回不到壓縮之前的狀態了。2.並查集合並時,小的往大的合併,啟發式合併。3.對於第i步 不管什麼操作 操作都要把root i roo i 1 我在合併時,如果兩個祖先一樣就直接continue了,沒把root i 賦值為root i 1 一直...
P3402 模板 可持久化並查集
今天看到這道題,忽然不知道為何要線段樹了 笑 出現了一些瞎搞的想法 然後就想到了操作樹。就是,我們可以離線,然後每個位置直接維護乙個棧,記錄歷史資訊。然鵝我也不知道為什麼常數很大 include define r register int using namespace std namespace ...