洛谷P3402 可持久化并查集
2024-10-07 02:03:49
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 ;
}
最新文章
- 所有的cursor图标
- Dynamics AX 2012 R2 窗体系列 - 在窗体上修改字段时所触发的方法及其顺序
- .NET Core下使用gRpc公开服务(SSL/TLS)
- POJ 1002	487-3279
- thinkphp实现导航高亮的简单方法
- 表单序列化 js
- Dijkstra + 优先队列优化 模板
- WCF - WAS Hosting
- C语言嵌入式系统编程修炼之二:软件架构篇
- OCA读书笔记(4) - 管理数据库实例
- Android 开发使用第三方库出现Crash时处理方案汇总
- CodeChef - ELHIDARR Find an element in hidden array(互动题)题解
- STL六大组件
- 快速开发QCombox以及业务样式自定义
- Data transfer from GPIO port to RAM buffer using DMA upon receiving a trigger signal on the timer capture input channel.
- Python学习(002)--Python介绍
- docker入门之基础操作
- 移动端推广APP防作弊机制之依我见
- 范浩强treap 普通平衡树
- 深入了解.Net上下文
热门文章
- SICK激光扫描仪LMS511连接通讯
- Windows 下关于转码的函数
- yolo3 车辆检测
- 【AMAD】betamax -- 一个ruby-VCR的模仿品,只支持requests
- 用yum安装的方法部署lamp服务
- 【OpenGL】初识OpenGL4.0
- GrapeCity Documents for Excel 与 Apache POI 功能对比
- oracle在group by时某列有多个值的拼接
- 爬取百度贴吧前1000页内容(requests库面向对象思想实现)
- springboot2.X版本得@Transactional注解事务不回滚不起作用