P3402 可持久化并查集题解
P3402 题解
题目传送门 P3402
题目大意
给定
有
-
1 a b合并a,b 所在集合; -
2 k回到第k 次操作(执行三种操作中的任意一种都记为一次操作)之后的状态; -
3 a b询问a,b 是否属于同一集合,如果是则输出1 ,否则输出0 。
题目分析
首先我们来学一一个非常方便,简洁,且高端的东西。
它就是 rope 。
什么是 rope ?它可以当做可持久化数据结构使用,其内部构造则是一个块状链表。
调用 rope 的时候需要头文件 #include<ext/rope>
当然,以后你还会学到别的和 rope 一样的操作,如果你不想背那么多头文件的话,可以使用 #include <bits/extc++.h>
注:#include<bits/stdc++.h> 头文件并不包含 #include <bits/extc++.h> 头文件。
仅仅这样是没有办法定义 rope 的。
我们还需要调用命名空间, using namespace __gnu_cxx;
注:__gnu_cxx 是一个新的空间,同头文件,它也是脱离了 namespace std 库的存在。
当然,我们也可以通过 __gnu_cxx::rope 来定义。
rope 的声明使用方式如下:
rope<int> arr;
struct SegmentTree
{
int l, r;
int id;
};
rope<node> t;
crope ch;//即 rope char;
在这道题中,我们需要了解 rope 的一个很强的函数功能 : replace
replace(p,x) : 从
这里插一句,rope 本身就是一个可持久化数组。
那么放到这个题呢?
直接写正常的并查集模板就行了啊!
实际写法开一堆数组,暴力维护即可,相同的做法也可以在 P6166 中尝试。
代码
此题数据范围略大,需要吸氧
#include <bits/stdc++.h>
#include <ext/rope>
//#define int long long
#define endl '\n'
#define rint register unsigned
using namespace __gnu_cxx;
using namespace std;
#define IN stdin->_IO_read_ptr < stdin->_IO_read_end ? *stdin->_IO_read_ptr++ : __uflow(stdin)
#define OUT(_ch) stdout->_IO_write_ptr < stdout->_IO_write_end ? *stdout->_IO_write_ptr++ = _ch : __overflow(stdout, _ch)
const int N = 2e5 + 5;
unsigned f[N];
unsigned r[N];
void read(unsigned &x)
{
x = 0;
char ch = IN;
while (ch < 47)
ch = IN;
while (ch > 47)
x = (x << 1) + (x << 3) + (ch & 15), ch = IN;
}
unsigned find(rope<unsigned> &fa, unsigned &i)
{
unsigned f = fa[i];
return f == i ? i : find(fa, f);
}
void merge(rope<unsigned> &fa, unsigned &a, unsigned &b)
{
a = find(fa, a);
b = find(fa, b);
if (a == b)
{
return ;
}
if (r[a] > r[b])
{
fa.replace(b, a);
}
else
{
if (r[a] == r[b])
{
r[b]++;
}
fa.replace(a, b);
}
}
signed main()
{
unsigned n, m, op, a, b;
read(n);
read(m);
rope<unsigned> fa[m + 1];
for (rint i = 1; i <= n; i++)
{
f[i] = i;
}
f[0] = 1;
fa[0] = rope<unsigned>(f);
for (rint i = 1; i <= m; i++)
{
read(op);
switch (op)
{
case 1:
fa[i] = fa[i - 1];
read(a);
read(b);
merge(fa[i], a, b);
break;
case 2:
read(a);
fa[i] = fa[a];
break;
default:
fa[i] = fa[i - 1];
read(a);
read(b);
OUT(find(fa[i], a) == find(fa[i], b) ? '1' : '0');
puts("");
}
}
return 0;
}
update (2022.8.21) : 感谢 @东灯 提供的快读让此代码在吸氧后无压力通过此题(不吸氧可得 78pts)