【模板】可持久化并查集
可持久化并查集
性质
可持久化并查集 = 可持久化数组 + 并查集 = 主席树 + 并查集
时间复杂度 \(O(n log^2 n)\)
\(Code\)
#include<cstdio>
#include<iostream>
using namespace std;
const int N = 2e5 + 5;
int n, m, cnt, fa[N * 32], dep[N * 32], rt[N];
struct node{int ls, rs;}tr[N * 32];
inline void read(int &x)
{
x = 0; int f = 1; char ch = getchar();
while (ch < '0' || ch > '9') f = (ch == '-' ? -1 : f), ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= f;
}
void build(int &p, int l, int r)
{
p = ++cnt;
if (l == r)
{
fa[p] = l;
return;
}
int mid = (l + r) >> 1;
build(tr[p].ls, l, mid);
build(tr[p].rs, mid + 1, r);
}
void update(int &u, int v, int l, int r, int x, int y)
{
u = ++cnt, tr[u] = tr[v];
if (l == r)
{
fa[u] = y, dep[u] = dep[v];
return;
}
int mid = (l + r) >> 1;
if (x <= mid) update(tr[u].ls, tr[v].ls, l, mid, x, y);
else update(tr[u].rs, tr[v].rs, mid + 1, r, x, y);
}
void Add(int p, int l, int r, int x)
{
if (l == r)
{
++dep[p];
return;
}
int mid = (l + r) >> 1;
if (x <= mid) Add(tr[p].ls, l, mid, x);
else Add(tr[p].rs, mid + 1, r, x);
}
int query(int p, int l, int r, int x)
{
if (l == r) return p;
int mid = (l + r) >> 1;
if (x <= mid) return query(tr[p].ls, l, mid, x);
else return query(tr[p].rs, mid + 1, r, x);
}
int find(int p, int x)
{
int y = query(p, 1, n, x);
if (fa[y] == x) return y;
return find(p, fa[y]);
}
int main()
{
read(n), read(m);
build(rt[0], 1, n);
for(register int i = 1, op, a, b; i <= m; i++)
{
read(op);
if (op == 1)
{
rt[i] = rt[i - 1];
read(a), read(b);
int x = find(rt[i], a), y = find(rt[i], b);
if (fa[x] == fa[y]) continue;
if (dep[x] > dep[y]) swap(x, y);
update(rt[i], rt[i - 1], 1, n, fa[x], fa[y]);
if (dep[x] == dep[y]) Add(rt[i], 1, n, fa[y]);
}
else if (op == 2) read(a), rt[i] = rt[a];
else{
read(a), read(b);
rt[i] = rt[i - 1];
if (fa[find(rt[i], a)] != fa[find(rt[i], b)]) printf("0\n");
else printf("1\n");
}
}
}