zz:https://www.cnblogs.com/cjoierljl/p/9567859.html

https://www.cnblogs.com/peng-ym/p/9357220.html

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

0<n,m<=2*10^4

Sample Input

5 6
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2

Sample Output

1
0
1

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<ctime>
#include<queue>
#include<stack>
#include<vector>
#define lst long long
#define ldb long double
#define N 200050
#define lson ljl[now].ls
#define rson ljl[now].rs
using namespace std;
const int Inf=1e9;
int read()
{
int s=0,m=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')m=1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return m?-s:s;
} int n,Q,tot;
int dep[N*30],fa[N*30];
int Edi[N];//版本编号
struct TREE{int ls,rs;}ljl[N*30];
//主席树部分
void Build(int &now,int le,int ri)
{
if(!now)now=++tot;
if(le==ri)
{
fa[now]=le;//第now个结点属于第le个集合
return;
}//并查集初始化
int mid=(le+ri)>>1;
Build(lson,le,mid);
Build(rson,mid+1,ri);
} void Update(int &now,int pre,int le,int ri,int loc,int ff)
//now代表新开线段树,pre是上一个线段树对应结点的编号
//loc及ff,是指将loc并到ff这个集合中
{
now=++tot;//新开log个节点
if(le==ri)
{
dep[now]=dep[pre];//copy过来
fa[now]=ff;//第now个结点属于ff集合
return;
}
lson=ljl[pre].ls,rson=ljl[pre].rs;//把前面的树“复制”过来
int mid=(le+ri)>>1;
if(loc<=mid)
Update(lson,ljl[pre].ls,le,mid,loc,ff);
else
Update(rson,ljl[pre].rs,mid+1,ri,loc,ff);
} int Query(int now,int le,int ri,int loc)
{//查到loc这个集合,在目前这个线段中的结点编号
if(le==ri)
return now;
int mid=(le+ri)>>1;
if(loc<=mid)
return Query(lson,le,mid,loc);
else
return Query(rson,mid+1,ri,loc);
}
void add(int now,int le,int ri,int loc)
{//按秩合并的树高改变
if(le==ri)
{
dep[now]++;
return;
}
int mid=(le+ri)>>1;
if(loc<=mid)
add(lson,le,mid,loc);
else
add(rson,mid+1,ri,loc);
} int Find_fa(int edi,int now)
{
int ff=Query(edi,1,n,now);
//查询在这一版本里now这个集合所在的结点编号
if(now==fa[ff])
//如果这个结点编号属于now这个集合,则找到
//如果不一样,则取出这个结点编号所指向的集合
return ff;
return Find_fa(edi,fa[ff]);//接着去找
} int main()
{
n=read(),Q=read();
Build(Edi[0],1,n);
for(int i=1;i<=Q;++i)
{
int opt=read();
if(opt==1)
{
Edi[i]=Edi[i-1];//先copy过来
int x=read(),y=read();
int fx=Find_fa(Edi[i],x);//取出结点编号
int fy=Find_fa(Edi[i],y);//同上
if(fa[fx]==fa[fy]) //如果是同一个集合
continue;
if(dep[fx]>dep[fy])
swap(fx,fy);//按秩合并,把x往y合并(dep小的往大的合并)
Update(Edi[i],Edi[i-1],1,n,fa[fx],fa[fy]);
//因为有合并操作,所以要新开线段树出来了
//注意后面两个参数是集合编号
if(dep[fx]+1>dep[fy])
add(Edi[i],1,n,fa[fy]);
}
if(opt==2)
{
int kk=read();
Edi[i]=Edi[kk];
}
if(opt==3)
{
Edi[i]=Edi[i-1];
int x=read(),y=read();
int fx=Find_fa(Edi[i],x),fy=Find_fa(Edi[i],y);
if(fa[fx]==fa[fy])
puts("1");
else
puts("0");
}
}
return 0;
}

  

最新文章

  1. RedHat6.5更新软件源
  2. MySQL带参数的存储过程小例子
  3. Android Fragment完全解析,关于碎片你所需知道的一切
  4. 与(and)&amp;&amp;
  5. hadoop浅尝 第一个hadoop程序
  6. 在HTML页面布局中,position的值有几种,默然的值是什么
  7. 为什么我选择使用 Blocks(块)
  8. Canvas使用渐变之-线性渐变详解
  9. 利用用户自己的server、tomcat下的解决iOS7.1企业应用无法安装应用程序 由于证书无效的问题
  10. Photon + Unity3D 在线游戏开发 学习笔记(两)
  11. jQuery形式可以计算,它包含了无线电的变化价格,select价格变化,删除行动态计算加盟
  12. RIPng(第三组)
  13. 洛谷 P3379 【模板】最近公共祖先(LCA)
  14. 高校表白APP-冲刺第一天
  15. Orchard详解--第四篇 缓存介绍
  16. [Leetcode 134]汽车加油站 Gas Station (环形)
  17. Linux -- 利用 ptrace 进行代码注入
  18. Linux基础命令---文本过滤coi
  19. 清除li内a标签的float=left实现a标签在li内居中显示(ul内li不居中显示)
  20. 七、并发容器ConcurrentHashMap

热门文章

  1. 最简洁地说明常用的git指令(1)
  2. Codeforces 981 共同点路径覆盖树构造 BFS/DP书架&amp;最大值
  3. 【NOIP2016提高A组模拟9.14】数列编辑器
  4. jvm——NIO
  5. 【curl】cookie的分隔符
  6. 在javascript中,如何判断一个被多次encode 的url 已经被decode到原来的格式?
  7. python 习题
  8. MySQL5.7数据转移至SQL Server详解
  9. UML——概述
  10. (49)LINUX应用编程和网络编程之四 Linux进程全解