[BZOJ3673]可持久化并查集 by zky
[BZOJ3673]可持久化并查集 by zky
试题描述
n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
0<n,m<=2*10^4
输入
见“试题描述”
输出
见“试题描述”
输入示例
5 6 1 1 2 3 1 2 2 0 3 1 2 2 1 3 1 2
输出示例
1 0 1
数据规模及约定
见“试题描述”
题解
用启发式合并的并查集,用主席树维护可持久化数组。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
}
#define maxn 20010
#define maxnode 1266666
int ToT, fa[maxnode], siz[maxnode], lc[maxnode], rc[maxnode];
void updatefa(int& y, int x, int l, int r, int p, int Fa) {
fa[y = ++ToT] = fa[x]; siz[y] = siz[x];
if(l == r){ fa[y] = Fa; return ; }
int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
if(p <= mid) updatefa(lc[y], lc[x], l, mid, p, Fa);
else updatefa(rc[y], rc[x], mid+1, r, p, Fa);
return ;
}
void updatesiz(int& y, int x, int l, int r, int p, int Siz) {
fa[y = ++ToT] = fa[x]; siz[y] = siz[x];
if(l == r){ siz[y] = Siz; return ; }
int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
if(p <= mid) updatesiz(lc[y], lc[x], l, mid, p, Siz);
else updatesiz(rc[y], rc[x], mid+1, r, p, Siz);
}
int qfa(int o, int l, int r, int p) {
if(!o) return 0;
if(l == r) return fa[o];
int mid = l + r >> 1;
if(p <= mid) return qfa(lc[o], l, mid, p);
return qfa(rc[o], mid+1, r, p);
}
int qsiz(int o, int l, int r, int p) {
if(!o) return 0;
if(l == r) return siz[o];
int mid = l + r >> 1;
if(p <= mid) return qsiz(lc[o], l, mid, p);
return qsiz(rc[o], mid+1, r, p);
}
int n, rt[maxn];
int findset(int o, int x) {
int tfa = qfa(o, 1, n, x);
return tfa == x ? x : findset(o, tfa);
}
int main() {
// freopen("data.in", "r", stdin);
n = read(); int q = read();
for(int i = 1; i <= n; i++)
updatefa(rt[0], rt[0], 1, n, i, i), updatesiz(rt[0], rt[0], 1, n, i, 1);
for(int i = 1; i <= q; i++) {
int tp = read();
if(tp == 1) {
int a = findset(rt[i-1], read()), b = findset(rt[i-1], read());
if(a == b){ rt[i] = rt[i-1]; continue; }
int sa = qsiz(rt[i-1], 1, n, a), sb = qsiz(rt[i-1], 1, n, b);
if(sa < sb) swap(a, b), swap(sa, sb);
updatefa(rt[i], rt[i-1], 1, n, b, a);
updatesiz(rt[i], rt[i], 1, n, a, sa + sb);
}
if(tp == 2) {
int k = read();
rt[i] = rt[k];
}
if(tp == 3) {
int a = findset(rt[i-1], read()), b = findset(rt[i-1], read());
// printf("%d %d\n", a, b);
puts(a == b ? "1" : "0");
rt[i] = rt[i-1];
}
// printf("ToT: %d\n", ToT);
}
return 0;
}

浙公网安备 33010602011771号