O - 土豆的集合
题目大意
查询某两个点是否联通,或者将某两个点联通,支持查询历史版本。
题解
如果不需要查询历史版本,那么显然就是并查集。
要支持历史版本,那就可持久化一下。
但是并查集不能路径压缩,为了保证时间复杂度,需要按秩合并。
- 注意:要及时更新
root
数组,即便是需要连接的两个点已经联通。
时间复杂度
按秩合并后的并查集,每一次查询是 O ( log n ) O(\log n) O(logn),可持久化的时间复杂度是 O ( log n ) O(\log n ) O(logn)。
因此,总的时间复杂度为 O ( m × log 2 n ) O(m\times \log^2 n) O(m×log2n)。
Tag
可持久化
并查集
code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define G getchar
#define ls(x) tr[x].l
#define rs(x) tr[x].r
#define s(x) tr[x].s
#define f(x) tr[x].fa
using namespace std;
int read()
{
char ch;
for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());
int n = 0 , w;
if (ch == '-')
{
w = -1;
ch = G();
} else w = 1;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n * w;
}
const int N = 300005;
int n , m , t , l , r , opv , tot , op , x , y , rt , ops , opf , ls;
int root[N * 100];
struct node
{
int l , r , s , fa;
}tr[N*100];
void ins (int x , int xx , int l , int r)
{
if (l == r)
{
f(xx) = opf;
s(xx) = ops;
return;
}
int m = (l + r) >> 1;
if (opv <= m)
{
rs(xx) = rs(x);
ls(xx) = ++ tot;
ins(ls(x) , ls(xx) , l , m);
}
else
{
rs(xx) = ++ tot;
ls(xx) = ls(x);
ins(rs(x) , rs(xx) , m + 1 , r);
}
}
int find (int x , int l , int r)
{
if (l == r) return x;
int m = (l + r) >> 1;
if (opv <= m)return find(ls(x) , l , m);
else return find(rs(x) , m + 1 , r);
}
int pos (int x)
{
opv = x;
return find(rt , 1 , n);
}
int get (int x)
{
int t = pos(x);
if (f(t) == x) return t;
else return get(f(t));
}
int main()
{
freopen("o.in","r",stdin);
//freopen("o.out","w",stdout);
n = read(); m = read();
ls = tot = 0;
ops = 1;
for (int i = 1; i <= n; ++i)
{
opf = opv = i;
root[0] = ++ tot;
ins(ls , tot , 1 , n);
ls = root[0];
}
for (int i = 1; i <= m; ++i)
{
op = read();
if (op == 2)
{
root[i] = root[read()];
continue;
}
l = read();
r = read();
if (op == 3)
{
rt = root[i] = root[i - 1];
x = get(l);
y = get(r);
if (f(x) ^ f(y))puts("0");
else puts("1");
}
else
{
rt = root[i - 1];
x = get(l);
y = get(r);
if (f(x) ^ f(y))
{
if (s(x) < s(y)) swap(x , y);
ls = ++ tot;
opv = f(y);
opf = f(x);
ops = s(y);
ins(root[i - 1] , ls , 1 , n);
root[i] = ++ tot;
opv = f(x);
opf = f(x);
ops = max(s(y) + 1 , s(x));
ins(ls , root[i] , 1 , n);
}else root[i] = rt;
}
}
}