n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
0
n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
0
这题最早我没有想明白。
wyfcyx神犇给我讲了一下,告诉我是可持久化线段树维护可持久化数组从而维护可持久化并查集。
我。。。。。并没懂。。。。。
然后神犇告诉我,其实可持久化线段树里维护的是并查集中的信息。一个fa,一个启发式合并的size。
并查集的Find操作就从可持久化线段树里找。
然后,秒懂。
#include
#define N 200010
#define M 2000010
#define rt return
using namespace std;
inline int ReadInt()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
struct Tree
{
int l, r, v, deep;
}t[M];
int root[N];
int n, m, size;
void build(int &k, int l, int r)
{
if(k == 0) k = ++ size;
if(l == r)
{
t[k].v = l;
rt;
}
int mid = (l + r) >> 1;
build(t[k].l, l, mid);
build(t[k].r, mid + 1, r);
}
void modify(int l, int r, int x, int &y, int pos, int val)
{
y = ++ size;
if(l == r)
{
t[y].v = val;
t[y].deep = t[x].deep;
rt;
}
t[y].l = t[x].l;
t[y].r = t[x].r;
int mid = (l + r) >> 1;
if(pos <= mid) modify(l, mid, t[x].l, t[y].l, pos, val);
else modify(mid + 1, r, t[x].r, t[y].r, pos, val);
}
int query(int k, int l, int r, int pos)
{
if(l == r) return k;
int mid = (l + r) >> 1;
if(pos <= mid)return query(t[k].l, l, mid, pos);
else return query(t[k].r, mid + 1, r, pos);
}
void add(int k, int l, int r, int pos)
{
if(l == r)
{
t[k].deep ++;
rt;
}
int mid = (l + r) >> 1;
if(pos <= mid) add(t[k].l, l, mid, pos);
else add(t[k].r, mid + 1, r, pos);
}
int Find(int k, int x)
{
int p = query(k, 1, n, x);
if(x == t[p].v)return p;
return Find(k,t[p].v);
}
int main()
{
n = ReadInt();
m = ReadInt();
build(root[0], 1, n);
for(int i = 1; i <= m; i ++)
{
int f, a, b, c;
f = ReadInt();
if(f == 1)
{
root[i] = root[i - 1];
a = ReadInt();
b = ReadInt();
int p = Find(root[i], a);
int q = Find(root[i], b);
if(t[p].v == t[q].v) continue;
if(t[p].deep > t[q].deep) swap(p,q);
modify(1, n, root[i - 1], root[i], t[p].v, t[q].v);
if(t[p].deep == t[q].deep) add(root[i], 1, n, t[q].v);
}
if(f == 2)
{
int k = ReadInt();
root[i] = root[k];
}
if(f == 3)
{
root[i] = root[i - 1];
a = ReadInt();
b = ReadInt();
int p = Find(root[i], a);
int q = Find(root[i], b);
if(t[p].v == t[q].v) printf("1\n");
else printf("0\n");
}
}
rt 0;
}