其实看看代码自己就可以懂。
注意: 1.并查集不压缩路径,压缩了就回不到压缩之前的状态了。
2.并查集合并时,小的往大的合并,启发式合并。
3.对于第i步(不管什么操作)操作都要把root[i] = roo[i-1]//我在合并时,如果两个祖先一样就直接continue了,没把root[i]赋值为root[i-1],一直没看出来,拖了一个多月才过。。。。
#include
#include
using namespace std;
int n, m, tot, fa[4000005], siz[4000005], root[200005], ls[4000005], rs[4000005];
int build(int o,int l,int r)
{
int nd = ++tot;
if(l == r)
{
fa[nd] = l; siz[nd] = 1; return nd;
}
int mid = (l + r) >> 1;
ls[nd] = build(o*2, l, mid);
rs[nd] = build(o*2+1, mid+1, r);
return nd;
}
int qurey_fa(int o, int l, int r, int pos)
{
if(l == r) return fa[o];
int mid = (l + r) >> 1;
if(mid >= pos) return qurey_fa(ls[o], l, mid, pos);
else return qurey_fa(rs[o], mid+1, r, pos);
}
int find(int x,int bb)
{
int ff = qurey_fa(root[bb],1,n,x);
if(ff == x) return x;
else return find(ff,bb);
}
int qurey_size(int o, int l, int r, int pos)
{
if(l == r) return siz[o];
int mid = (l + r) >>1;
if(mid >= pos) return qurey_size(ls[o], l, mid, pos);
else return qurey_size(rs[o], mid+1, r, pos);
}
int modify_fa(int o, int l, int r, int pos, int val)
{
int nd = ++tot;
rs[nd] = rs[o]; ls[nd] = ls[o]; fa[nd] = fa[o]; siz[nd] = siz[o];
if(l == r)
{
fa[nd] = val; return nd;
}
int mid = (l + r) >> 1;
if(pos <= mid) ls[nd] = modify_fa(ls[o], l, mid, pos, val);
else rs[nd] = modify_fa(rs[o], mid+1, r, pos, val);
return nd;
}
int modify_size(int o, int l, int r, int pos, int val)
{
int nd = ++tot;
rs[nd] = rs[o]; ls[nd] = ls[o]; fa[nd] = fa[o]; siz[nd] = siz[o];
if(l == r)
{
siz[nd] += val; return nd;
}
int mid = (l + r) >> 1;
if(pos <= mid)ls[nd] = modify_size(ls[o], l, mid, pos, val);
else rs[nd] = modify_size(rs[o], mid+1, r, pos, val);
return nd;
}
int main()
{
cin >> n >> m;
root[0] = build(1,1,n);//建树,把fa[i] 赋值为i
for(int i = 1; i <= m; i++)
{
int a,b,c; scanf("%d", &a);
if(a == 1)
{
scanf("%d%d", &b, &c);
int r1 = find(b,i-1); int r2 = find(c,i-1);//寻找i-1步时c的祖先是谁
if(r1 == r2){root[i] = root[i-1]; continue;}//如果祖先一样,continue;
int s1 = qurey_size(root[i-1],1,n,r1);
int s2 = qurey_size(root[i-1],1,n,r2);//询问大小
if(s1 < s2){ swap(s1,s2); swap(r1,r2);}//启发式合并。小合大,我规定r1大
root[i] = modify_fa(root[i-1],1,n,r2,r1);//把r2的爸爸改为r1,只改r2.
root[i] = modify_size(root[i],1,n,r1,s2);//把r1并查集的大小加上r2并查集的大小
}
else if(a == 2) {scanf("%d",&b); root[i] = root[b];}//回到操作b。
else
{
scanf("%d%d", &b, &c);
root[i] = root[i-1];
int r1 = find(b,i-1); int r2 = find(c,i-1);
if(r1 == r2) cout << "1" << endl;
else cout << "0"<