n个集合 m个操作

操作:

  • 1 a b 合并a,b所在集合

  • 2 k 回到第k次操作之后的状态(查询算作操作)

  • 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

说是可持久化并查集,实际上是把并查集的所有find和merge操作都放到可持久化数组上做,这样可以做到完全可持久化(不仅能查询某个历史版本,而且还能在某个历史版本的基础上进行修改)

注意并查集要按秩合并

可持久化数组可以用可持久化线段树(主席树)或者可持久化平衡树实现,理论上平衡树应该更快一些而且更省内存(但也省不了多少)

线段树版:

 #include<bits/stdc++.h>
using namespace std;
const int N=2e5+;
int rt[N],fa[N*],mxd[N*],ls[N*],rs[N*],tot,n,m;
#define mid ((l+r)>>1)
int cpy(int v) {int u=++tot; fa[u]=fa[v],mxd[u]=mxd[v],ls[u]=ls[v],rs[u]=rs[v]; return u;}
int qry(int* a,int p,int& u,int l=,int r=n) {
if(l==r)return a[u];
return p<=mid?qry(a,p,ls[u],l,mid):qry(a,p,rs[u],mid+,r);
}
void upd(int* a,int p,int x,int v,int& u,int l=,int r=n) {
u=cpy(v);
if(l==r) {a[u]=x; return;}
p<=mid?upd(a,p,x,ls[v],ls[u],l,mid):upd(a,p,x,rs[v],rs[u],mid+,r);
}
int fd(int x,int u) {
int fx=qry(fa,x,u);
return fx?fd(fx,u):x;
}
void mg(int x,int y,int& u) {
int fx=fd(x,u),fy=fd(y,u);
if(fx==fy)return;
int dx=qry(mxd,fx,u),dy=qry(mxd,fy,u);
if(dx>dy)swap(fx,fy),swap(dx,dy);
upd(fa,fx,fy,u,u);
if(dx==dy)upd(mxd,fy,dx+,u,u);
}
int main() {
mxd[]=;
scanf("%d%d",&n,&m);
for(int i=; i<=m; ++i) {
rt[i]=rt[i-];
int f,x,y;
scanf("%d",&f);
if(f==)scanf("%d%d",&x,&y),mg(x,y,rt[i]);
else if(f==)scanf("%d",&x),rt[i]=rt[x];
else scanf("%d%d",&x,&y),printf("%d\n",fd(x,rt[i])==fd(y,rt[i]));
}
return ;
}

平衡树版:(由于没有旋转分裂等操作所以代码和线段树基本没区别,只是二分判断的条件稍微改了一下)

 #include<bits/stdc++.h>
using namespace std;
const int N=2e5+;
int rt[N],fa[N*],mxd[N*],ls[N*],rs[N*],tot,n,m;
#define mid ((l+r)>>1)
int cpy(int v) {int u=++tot; fa[u]=fa[v],mxd[u]=mxd[v],ls[u]=ls[v],rs[u]=rs[v]; return u;}
int qry(int* a,int p,int& u,int l=,int r=n) {
if(p==mid)return a[u];
return p<mid?qry(a,p,ls[u],l,mid-):qry(a,p,rs[u],mid+,r);
}
void upd(int* a,int p,int x,int v,int& u,int l=,int r=n) {
u=cpy(v);
if(p==mid) {a[u]=x; return;}
p<mid?upd(a,p,x,ls[v],ls[u],l,mid-):upd(a,p,x,rs[v],rs[u],mid+,r);
}
int fd(int x,int u) {
int fx=qry(fa,x,u);
return fx?fd(fx,u):x;
}
void mg(int x,int y,int& u) {
int fx=fd(x,u),fy=fd(y,u);
if(fx==fy)return;
int dx=qry(mxd,fx,u),dy=qry(mxd,fy,u);
if(dx>dy)swap(fx,fy),swap(dx,dy);
upd(fa,fx,fy,u,u);
if(dx==dy)upd(mxd,fy,dx+,u,u);
}
int main() {
mxd[]=;
scanf("%d%d",&n,&m);
for(int i=; i<=m; ++i) {
rt[i]=rt[i-];
int f,x,y;
scanf("%d",&f);
if(f==)scanf("%d%d",&x,&y),mg(x,y,rt[i]);
else if(f==)scanf("%d",&x),rt[i]=rt[x];
else scanf("%d%d",&x,&y),printf("%d\n",fd(x,rt[i])==fd(y,rt[i]));
}
return ;
}

洛谷P3402 可持久化并查集的更多相关文章

  1. bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集

    题目:bzoj3673:https://www.lydsy.com/JudgeOnline/problem.php?id=3673 bzoj3674:https://www.lydsy.com/Jud ...

  2. P3402 可持久化并查集

    P3402 通过主席树维护不同版本的并查集,注意要采用按秩合并的方式,路径压缩可能会爆. 1 #include <bits/stdc++.h> 2 using namespace std; ...

  3. 洛谷 3295 [SCOI2016]萌萌哒——并查集优化连边

    题目:https://www.luogu.org/problemnew/show/P3295 当要连的边形如 “一段区间内都是 i 向 i+L 连边” 的时候,用并查集优化连边. 在连边的时候,如果要 ...

  4. 洛谷P2024 食物链 [NOI2001] 并查集

    正解:并查集 解题报告: 传送门(咕了! 其实没有很难(虽然我是交了三发才过的QAQ 但是一来好久没打并查集了恢复一下智力 二来看着智推里唯一一个蓝就很不爽(,,,虽然做了这题之后又补上了个蓝题QAQ ...

  5. 洛谷P1197 [JSOI2008] 星球大战 [并查集]

    题目传送门 星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这 ...

  6. 洛谷 P1551 亲戚(并查集模板)

    嗯... 题目链接:https://www.luogu.org/problemnew/show/P1551 思路: 很显然地我们会发现,这是一道并查集的模板题,并且是考察了并查集中的”并“和”查“的操 ...

  7. 洛谷P1111修复公路并查集改

    看了他们的题解感觉很震惊,为什么要用kruskal,这题要用到最小生成树吗??? 38行短短的程序就可以了,我觉得学习不是一种套用,套自己学的,而且题解很大一部分都是kruskal. 个人认为自己的程 ...

  8. 洛谷P1525关押罪犯——并查集

    题目:https://www.luogu.org/problemnew/show/P1525 并查集+贪心,从大到小排序,将二人分在不同房间,找到第一个不满足的即为答案. 代码如下: #include ...

  9. 洛谷 - P5429 - Fence Planning - 并查集

    https://www.luogu.org/problemnew/show/P5429 很明显是要维护整个连通块的共同性质,并查集一搞就完事了. #include<bits/stdc++.h&g ...

随机推荐

  1. Linux 学习路径

    Linux learning path Mind Map graph LR A[Linux学习路径]-->b[计算机概论与硬件相关知识] A -->c[Linux 初级] A --> ...

  2. NativeContainer

    安全系统复制数据的过程的缺点是它还隔离了每个副本中作业的结果.要克服此限制,您需要将结果存储在一种名为NativeContainer的共享内存中. 什么是NativeContainer? A Nati ...

  3. umask的一般用法

    常常会遇到我的Linux系统默认的八进制的umask值是0022,而我创建的文件的八进制权限却是644,这个是怎么一回事? umask值只是一个掩码,它会屏蔽掉掉不想授予该安全级别的权限. 用法是要把 ...

  4. ubuntu 16.04 server 扩容(LVM)磁盘

    因为发现我的本地server出现磁盘满了的情况 所以进行lvm的扩容 1 查看磁盘情况 df -h 原本发现 /dev/mapper/ubuntu1604--vg-root 这个磁盘满了 所以要进行扩 ...

  5. CTR点击率校准

    1. 概述 广告CTR预估过程中,正负样本比例差距较大,需要采样,但是采用后模型训练的结果是有偏的. 2. 校准方式 用逻辑回归作为激活函数

  6. 【转贴】龙芯内核发展策略 已经支持k8s

    龙芯内核发展策略 时间:2019-06-27 15:48  来源:未知   作者:龙芯中科   点击:1002次 http://www.loongson.cn/m/view.php?aid=1118 ...

  7. oracle数据区间

    区是段下面的一个管理单位,一个区在物理上是一段连续的数据块. 一个数据文件有一个文件头,它用了若干个数据块,这个文件头里记录着区的分配与释放的信息.在这个文件中有些区是被使用的,有些区是空闲的. 什么 ...

  8. redis 学习(1)-- redis 安装与启动

    redis 学习(1)-- redis 安装与启动 redis 特性 关于 redis 的介绍网上已经有很多信息了,这里我就不在详细说明了.介绍一下几个鲜明特性: 1.速度快 官方称可以达到10W的q ...

  9. C++ 多态、虚函数(virtual 关键字)、静态联编、动态联编

    函数重写:(在子类中重写父类中的函数) 父类中被重写的函数  依然会继承  给子类. 子类中重写的函数将覆盖父类中的函数. 通过作用域分辨符  ::  可以访问到父类中的函数. 例如: #includ ...

  10. centos配置postfix邮件服务

    1.环境初始化 [root@mail ~]# rpm -q centos-release //查看系统版本 centos-release-7-5.1804.el7.centos.x86_64 [roo ...