bzoj 3674: 可持久化并查集加强版
Description:
自从zkysb出了可持久化并查集后……
hzwer:乱写能AC,暴力踩标程
KuribohG:我不路径压缩就过了!
ndsf:暴力就可以轻松虐!
zky:……
n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为0
0
Sample Input
5 6
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2
Sample Output
1
0
1
知识点:可持久化并查集
这是一道模板题。
可持久化并查集还蛮好玩的。
就是相当于用主席树搞一个可持久化数组,维护f和h值。f是在并查集里面的父亲,h是启发式合并的秩。
虽然说理论上启发式合并+路径压缩会快,可是只开启发式合并好像实测更快。
算了不管了,就这样吧。
代码
这个是路径压缩+启发式合并的可持久化并查集。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
const int N = 220000, T = 1e7 + 10;
int read() {
char ch = getchar();int x = 0, f = 1;
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;
}
int n, m, sz;
int rt[N], ls[T], rs[T], f[T], h[T];
void Build(int &p, int L, int R) {
p = ++sz;
if(L == R) {f[p] = L; return;}
int mid = L + R >> 1;
Build(ls[p], L, mid);
Build(rs[p], mid + 1, R);
}
void Modify(int lp, int &cp, int L, int R, int pos, int val) {
cp = ++sz;
if(L == R) {f[cp] = val; h[cp] = h[lp]; return ;}
int mid = L + R >> 1;
if(pos <= mid) rs[cp] = rs[lp], Modify(ls[lp], ls[cp], L, mid, pos, val);
else ls[cp] = ls[lp], Modify(rs[lp], rs[cp], mid + 1, R, pos, val);
}
void Add(int p, int L, int R, int pos) {
if(L == R) {++h[p]; return;}
int mid = L + R >> 1;
if(pos <= mid) Add(ls[p], L, mid, pos);
else Add(rs[p], mid + 1, R, pos);
}
int Query(int p, int L, int R, int pos) {
if(L == R) return p;
int mid = L + R >> 1;
if(pos <= mid) return Query(ls[p], L, mid, pos);
else return Query(rs[p], mid + 1, R, pos);
}
int F(int k, int x) {
int p = Query(k, 1, n, x);
if(x == f[p]) return p;
int t = F(k, f[p]);
Modify(k, k, 1, n, f[p], t);
return t;
}
void Merge(int i, int u, int v) {
int p = F(rt[i], u), q = F(rt[i], v);
if(f[p] == f[q]) return;
if(h[p] < h[q]) swap(p, q);
Modify(rt[i - 1], rt[i], 1, n, f[q], f[p]);
if(h[p] == h[q]) Add(rt[i], 1, n, f[p]);
}
int main() {
n = read(); m = read();
Build(rt[0], 1, n);
for(int i = 1;i <= m; ++i) {
int opt = read();
if(opt == 2) {rt[i] = rt[read()];}
else {
int x = read(), y = read();
rt[i] = rt[i - 1];
if(opt == 1) Merge(i, x, y);
else printf("%d\n", f[F(rt[i], x)] == f[F(rt[i], y)] ? 1 : 0);
}
}
return 0;
}