题目:
http://www.lydsy.com/JudgeOnline/problem.php?id=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
思路:
bzoj 3673的加强版。。。就没了。。。
#include <bits/stdc++.h>
using namespace std;
const int N = 200000 + 10, M = 5000000 + 10, INF = 0x3f3f3f3f;
int root[N], lson[M], rson[M], par[M], rnk[M];
int tot;
int n;
void build(int l, int r, int &x)
{
x = ++tot;
if(l == r)
{
par[x] = l; return;
}
int mid = (l + r) >> 1;
build(l, mid, lson[x]);
build(mid + 1, r, rson[x]);
}
int query(int l, int r, int p, int x)
{
if(l == r) return x;
int mid = (l + r) >> 1;
if(p <= mid) return query(l, mid, p, lson[x]);
else return query(mid + 1, r, p, rson[x]);
}
void update(int l, int r, int pos, int val, int pre, int &x)
{
x = ++tot;
lson[x] = lson[pre], rson[x] = rson[pre];
if(l == r)
{
par[x] = val, rnk[x] = rnk[pre]; return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(l, mid, pos, val, lson[pre], lson[x]);
else update(mid + 1, r, pos, val, rson[pre], rson[x]);
}
void add_rnk(int l, int r, int pos, int x)
{
if(l == r)
{
rnk[x]++; return;
}
int mid = (l + r) >> 1;
if(pos <= mid) add_rnk(l, mid, pos, lson[x]);
else add_rnk(mid + 1, r, pos, rson[x]);
}
int ufs_find(int p, int x)
{
int r;
while(true)
{
r = query(1, n, p, x);
if(p == par[r]) break;
p = par[r];
}
return r;
}
//int ufs_find(int p, int x)
//{
// int r = query(1, n, p, x);
// if(p == par[r]) return r;
// else return ufs_find(par[r], x);
//}
//int ufs_find(int p, int x)//还是别路径压缩的好。。。
//{
// int r = query(1, n, p, x);
// if(p == par[r]) return r;
// int t = ufs_find(par[r], x);
// update(1, n, par[r], t, x, x);
// return t;
//}
int main()
{
int m, op, a, b, ans = 0;
scanf("%d%d", &n, &m);
tot = 0;
build(1, n, root[0]);
for(int i = 1; i <= m; i++)
{
scanf("%d", &op);
if(op == 1)
{
root[i] = root[i-1];
scanf("%d%d", &a, &b);
a ^= ans, b ^= ans;
int pa = ufs_find(a, root[i-1]), pb = ufs_find(b, root[i-1]);
if(par[pa] == par[pb]) continue;
if(rnk[pa] > rnk[pb]) swap(pa, pb);
update(1, n, par[pa], par[pb], root[i-1], root[i]);
if(rnk[pa] == rnk[pb]) add_rnk(1, n, par[pb], root[i]);
}
else if(op == 2)
{
scanf("%d", &a);
a ^= ans;
root[i] = root[a];
}
else
{
root[i] = root[i-1];
scanf("%d%d", &a, &b);
a ^= ans, b ^= ans;
int pa = ufs_find(a, root[i-1]), pb = ufs_find(b, root[i-1]);
if(par[pa] == par[pb]) ans = 1;
else ans = 0;
printf("%d\n", ans);
}
}
return 0;
}
//贴个rope版的,实现超级简单
#include <bits/stdc++.h>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
const int N = 200000 + 10;
rope<int> *par[N];
int a[N];
int Find(int x, int cur)
{
int r = x, i = x, j;
while(r != par[cur]->at(r)) r = par[cur]->at(r);
while(par[cur]->at(i) != r) j = par[cur]->at(i), par[cur]->replace(i, r), i = j;
return r;
}
void unite(int x, int y, int cur)
{
x = Find(x, cur), y = Find(y, cur);
if(x == y) return;
par[cur]->replace(x, y);
}
bool same(int x, int y, int cur)
{
return Find(x, cur) == Find(y, cur);
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; i++) a[i] = i;
par[0] = new rope<int>(a, a + 1 + n);
int opt, x, y, ans = 0;
for(int i = 1; i <= m; i++)
{
par[i] = new rope<int>(*par[i-1]);
scanf("%d", &opt);
if(opt == 1)
{
scanf("%d%d", &x, &y);
x ^= ans, y ^= ans;
unite(x, y, i);
}
else if(opt == 2)
{
scanf("%d", &x);
x ^= ans;
par[i] = new rope<int>(*par[x]);
}
else if(opt == 3)
{
scanf("%d%d", &x, &y);
x ^= ans, y ^= ans;
ans = same(x, y, i);
printf("%d\n", ans);
}
}
return 0;
}