Description
n个集合 m个操作
操作:
-
1 a b
合并ab所在集合 -
2 k
回到第k次操作之后的状态(查询算作操作) -
3 a b
询问ab是否属于同一集合,是则输出1否则输出0
5 6 1 1 2 3 1 2 2 0 3 1 2 2 1 3 1 2
-
Sample Input
1 0 1
-
Sample Output
HINT
1≤n≤1051≤m≤2×105
By zky 出题人大神犇
Source/Category
没有路径压缩!(慢死了),直接启发式合并
主席树维护父亲深度
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 100010;
int n, lc[MAXN*60], rc[MAXN*60], val[MAXN*60], dep[MAXN*60], root[MAXN*2], id = 0;
void build(int &rt, int l, int r) { // 建主席树
rt = ++id;
if (l==r) {
val[rt] = 0; dep[rt] = 1; return;
}
int m = (l+r) >> 1;
build(lc[rt], l, m); build(rc[rt], m+1, r);
}
void update(int &rt, int old_rt, int l, int r, int x, int v) { // 更新父亲
rt = ++id; lc[rt] = lc[old_rt]; rc[rt] = rc[old_rt]; // 新建节点
if (l==r) {
val[rt] = v; dep[rt] = dep[old_rt]; return;
}
int m = (l+r) >> 1;
if (x<=m) update(lc[rt], lc[old_rt], l, m, x, v);
else update(rc[rt], rc[old_rt], m+1, r, x, v);
}
void update_dep(int rt, int l, int r, int x) { // 更新深度
if (l==r) {
++dep[rt]; return;
}
int m = (l+r) >> 1;
if (x<=m) update_dep(lc[rt], l, m, x);
else update_dep(rc[rt], m+1, r, x);
}
int query(int rt, int l, int r, int x) { // 查询(下标)
if (l==r) return rt; // 返回
int m = (l+r) >> 1;
if (x<=m) return query(lc[rt], l, m, x);
else return query(rc[rt], m+1, r, x);
}
int find(int ed, int x) { // 找祖先
int fa = val[query(root[ed], 1, n, x)];
if (fa) return find(ed, fa);
else return x;
}
int main() {
int m; scanf("%d%d", &n, &m);
build(root[0], 1, n);
for (int i=1; i<=m; ++i) {
int op, a, b; scanf("%d%d", &op, &a);
if (op==1) {
scanf("%d", &b);
a = find(i-1, a); b = find(i-1, b);
if (a==b) {
root[i] = root[i-1]; continue;
}
int p = query(root[i-1], 1, n, a); // 合并
int p2 = query(root[i-1], 1, n, b);
int s = dep[p];
int s2 = dep[p2];
if (s>s2) { // 启发式合并,深度小的合并到深度大的上
swap(a, b); swap(s, s2);
}
update(root[i], root[i-1], 1, n, a, b);
update_dep(root[i], 1, n, b); // 更新深度
}
else if (op==2) root[i] = root[a]; // 回到某个版本
else {
scanf("%d", &b); root[i] = root[i-1]; // 查询是否在同一集合
if (find(i, a)==find(i, b)) printf("1\n");
else printf("0\n");
}
}
return 0;
}