题意:
3种操作
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
做法:
可持久化并查集,相当于每个时间建一棵线段树维护每个数的fa[]。
这题我用了按秩合并。
这么理解,把并查集看成很多棵树,先不考虑路径压缩。
如果两个节点要合并,相当于把他们所在的两棵树合并。假定两个树的根节点为fx,fy。
秩就是树的最大深度。
按秩合并意思就是把深度小的接到深度大的那个节点上去,即fa[fx]=fy。
假如两棵树深度相同,那么其中一棵树的深度要加1.
这样大概可以快一点。
然后应该也可以维护一棵树的size,每次把size小的加到size大的里面去。
代码:
/*************************************************************
Problem: bzoj 3674 可持久化并查集加强版
User: fengyuan
Language: C++
Result: Accepted
Time: 1828 ms
Memory: 158324 kb
Submit_Time: 2017-12-29 14:10:53
*************************************************************/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define mid ((l+r)/2)
using namespace std;
const int N = 200010, M = 10000010;
int n, m, tot, now;
int fa[M], rt[N], L[M], R[M], h[M];
inline void build(int &rt, int l, int r)
{
rt = ++ tot;
if(l == r) { fa[rt] = l; return; }
build(L[rt], l, mid); build(R[rt], mid+1, r);
}
inline int query(int rt, int l, int r, int x)
{
if(l == r) return rt;
if(x <= mid) return query(L[rt], l, mid, x); else return query(R[rt], mid+1, r, x);
}
inline int getFa(int rt, int x)
{
int p = query(rt, 1, n, x);
if(x == fa[p]) return p; else return getFa(rt, fa[p]);
}
inline void modify(int pre, int &rt, int l, int r, int x, int y)
{
rt = ++ tot;
if(l == r) {
fa[rt] = y; h[rt] = h[pre];
return;
}
L[rt] = L[pre]; R[rt] = R[pre];
if(x <= mid) modify(L[pre], L[rt], l, mid, x, y); else modify(R[pre], R[rt], mid+1, r, x, y);
}
inline void inc(int rt, int l, int r, int x)
{
if(l == r) { h[rt] ++; return; }
if(x <= mid) inc(L[rt], l, mid, x); else inc(R[rt], mid+1, r, x);
}
inline void merge(int x, int y)
{
if(h[x] > h[y]) swap(x, y);//按秩合并
modify(rt[now-1], rt[now], 1, n, fa[x], fa[y]);
if(h[x] == h[y]) inc(rt[now], 1, n, fa[y]);
}
int main()
{
scanf("%d%d", &n, &m);
build(rt[0], 1, n);
int lastans = 0;
for(int i = 1; i <= m; i ++) {
int opt, x, y; scanf("%d%d", &opt, &x); x ^= lastans;
if(opt == 2) { rt[i] = rt[x]; continue; }
scanf("%d", &y); y ^= lastans;
rt[i] = rt[i-1]; now = i;
int fx = getFa(rt[now], x), fy = getFa(rt[now], y);
if(opt == 1) { if(fa[fx] != fa[fy]) merge(fx, fy); }
else {
lastans = fa[fx] == fa[fy];
printf("%d\n", lastans);
}
}
return 0;
}