可撤销并查集

const int N = 2e5 + 5;
struct DSU {
struct Info {
int u, v, add;
};
vector<int> p, h;
vector<Info> st;
int idx = 0;
DSU(int n) {
p.resize(n + 1);
h.resize(n + 1);
iota(p.begin(), p.end(), 0);
}
void init(int n) {
p.resize(n + 1);
h.resize(n + 1);
iota(p.begin(), p.end(), 0);
}
int find(int x){
while (x != p[x]) {
x = p[x];
}
return p[x];
}
void merge(int u, int v){
int fu = find(u);
int fv = find(v);
if (fu == fv){
return;
}
if (h[fu] > h[fv]){
swap(fu, fv);
}
st.emplace_back(fu, fv, h[fu] == h[fv]);
idx++;
p[fu] = fv;
if (h[fu] == h[fv]) {
h[fv]++;
}
}
void restore(int t){ // 回溯到 t 时刻
while (st.size() > t){
resume();
}
}
void resume() {
auto [u, v, add] = st.back();
h[v] -= add;
p[u] = u;
st.pop_back();
idx--;
}
} dsu(N);
// 这里取决于维护的点数!