前言
要学可持久化并查集,必须先会可持久化数组。
L i n k Link Link
可持久化数组详见博客可持久化专题(二)——可持久化数组的实现
简介
可持久化并查集应该是一个挺实用的数据结构(例如NOI2018Day1T1中就有它的身影)。
它主要建立于可持久化数组的基础之上(而可持久化数组的实现是完全基于主席树的),因为这样就可以去访问一些历史版本从而实现可持久化了。
L i n k Link Link
主席树详见博客可持久化专题(一)——浅谈主席树:可持久化线段树
按秩合并
由于可持久化的缘故,我们要切记,可持久化并查集是不能像普通并查集一样写路径压缩的!
或许有人会问,不路径压缩,还不 T T T飞?
没关系,没有路径压缩,我们还有按秩合并,它的复杂度均摊是 O ( l o g n ) O(logn) O(logn)的,平时由于已经有路径压缩了,
所以基本上没人写按秩合并(实在没什么必要,时间复杂度优化并不大),而此时此刻,没法用路径压缩,按秩合并就起了很大的作用。
L i n k Link Link
按秩合并的复杂度证明详见博客启发式合并
具体实现
如果对可持久化并查集还有什么不懂的,最好再多思考一下,毕竟这还是有点深奥的。
下面是洛谷上可持久化并查集板子题的代码:(代码比可持久化数组长了许多)
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define LL long long
#define swap(x,y) (x^y?(x^=y,y^=x,x^=y):0)
#define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
#define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
#define N 200000
int pp_=0;char ff[100000],*A=ff,*B=ff,pp[100000];
using namespace std;
int n,Q,tot=0,rt[N+5],a[N+5];
struct Chairman_Tree
{
int Son