洛谷P3402 【模板】可持久化并查集 [主席树,并查集]
可持久化并查集
n个集合 m个操作
操作:
1 a b
合并a,b所在集合2 k
回到第k次操作之后的状态(查询算作操作)3 a b
询问a,b是否属于同一集合,是则输出1否则输出0
输入输出格式
输入格式:
输出格式:
输入输出样例
- 5 6
- 1 1 2
- 3 1 2
- 2 0
- 3 1 2
- 2 1
- 3 1 2
- 1
- 0
- 1
说明
$1 \le n \le 10^5, 1 \le m \le 2 \times 10^5$
By zky 出题人大神犇
分析:
解锁并查集的新姿势——可持久化并查集。
其实大部分的可持久化数据结构都是可以由主席树和可持久化平衡树实现的,所以只要能把主席树理解透彻了,其他的也差不多就不难理解了。本体的关键在于用主席树维护并查集的$fa[]$数组,同时还要注意不能路径压缩,否则会挂的很惨。另外,为了保证时间复杂度,还需要采用按秩合并,$rk[]$数组同样用主席树维护。
Code:
- //It is made by HolseLee on 8th Aug 2018
- //Luogu.org P3402
- #include<cstdio>
- #include<cstring>
- #include<cstdlib>
- #include<cmath>
- #include<iostream>
- #include<iomanip>
- #include<algorithm>
- #pragma GCC optimize(2)
- using namespace std;
- const int N=1e5+;
- int n,m,tot,fa[N*],rk[N*],root[N*];
- struct Seg{
- int ls,rs;
- };
- struct President{
- Seg t[N*];
- inline void build(int &rt,int l,int r)
- {
- rt=++tot;
- if(l==r){
- fa[rt]=l;return;
- }
- int mid=(l+r)>>;
- build(t[rt].ls,l,mid);
- build(t[rt].rs,mid+,r);
- }
- inline void update(int &rt,int las,int l,int r,int pos,int f)
- {
- rt=++tot;t[rt].ls=t[las].ls,t[rt].rs=t[las].rs;
- if(l==r){
- fa[rt]=f;rk[rt]=rk[las];
- return;
- }
- int mid=(l+r)>>;
- if(pos<=mid)update(t[rt].ls,t[las].ls,l,mid,pos,f);
- else update(t[rt].rs,t[las].rs,mid+,r,pos,f);
- }
- inline int quary(int rt,int l,int r,int pos)
- {
- if(l==r)return rt;
- int mid=(l+r)>>;
- if(pos<=mid)return quary(t[rt].ls,l,mid,pos);
- else return quary(t[rt].rs,mid+,r,pos);
- }
- inline int find(int i,int x)
- {
- int f=quary(root[i],,n,x);
- if(x==fa[f])return f;
- return find(i,fa[f]);
- }
- inline void pushup(int rt,int l,int r,int pos)
- {
- if(l==r){
- rk[rt]++;
- return;
- }
- int mid=(l+r)>>;
- if(pos<=mid)pushup(t[rt].ls,l,mid,pos);
- else pushup(t[rt].rs,mid+,r,pos);
- }
- }T;
- inline int read()
- {
- char ch=getchar();int num=;bool flag=false;
- while(ch<''||ch>''){if(ch=='-')flag=true;ch=getchar();}
- while(ch>=''&&ch<=''){num=num*+ch-'';ch=getchar();}
- return flag?-num:num;
- }
- int main()
- {
- n=read();m=read();
- T.build(root[],,n);
- int op,x,y;
- for(int i=;i<=m;++i){
- op=read();
- switch (op){
- case : root[i]=root[i-];
- x=read(),y=read();x=T.find(i,x),y=T.find(i,y);
- if(fa[x]==fa[y])continue;
- if(rk[x]>rk[y])swap(x,y);
- T.update(root[i],root[i-],,n,fa[x],fa[y]);
- if(rk[x]==rk[y])T.pushup(root[i],,n,fa[y]);
- break;
- case :
- x=read();root[i]=root[x];
- break;
- case : root[i]=root[i-];
- x=read(),y=read();x=T.find(i,x),y=T.find(i,y);
- if(fa[x]==fa[y])printf("1\n");else printf("0\n");
- break;
- }
- }
- return ;
- }
洛谷P3402 【模板】可持久化并查集 [主席树,并查集]的更多相关文章
- 洛谷P3834 [模板]可持久化线段树1(主席树) [主席树]
题目传送门 可持久化线段树1(主席树) 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定 ...
- 洛谷P4559 [JSOI2018]列队 【70分二分 + 主席树】
题目链接 洛谷P4559 题解 只会做\(70\)分的\(O(nlog^2n)\) 如果本来就在区间内的人是不用动的,区间右边的人往区间最右的那些空位跑,区间左边的人往区间最左的那些空位跑 找到这些空 ...
- 洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)
题目链接 //离散化后范围1~cnt不要错 #include<cstdio> #include<cctype> #include<algorithm> //#def ...
- 洛谷.3835.[模板]可持久化平衡树(fhq treap)
题目链接 对每次Merge(),Split()时产生的节点都复制一份(其实和主席树一样).时间空间复杂度都为O(qlogq).(应该更大些 因为rand()?内存真的爆炸..) 对于无修改的操作实际上 ...
- ☆ [洛谷P2633] Count on a tree 「树上主席树」
题目类型:主席树+\(LCA\) 传送门:>Here< 题意:给出一棵树.每个节点有点权.问某一条路径上排名第\(K\)小的点权是多少 解题思路 类似区间第\(K\)小,但放在了树上. 考 ...
- 【洛谷 P2633】 Count on a tree(主席树,树上差分)
题目链接 思维难度0 实现难度7 建出主席树后用两点的状态减去lca和lca父亲的状态,然后在新树上跑第\(k\)小 #include <cstdio> #include <cstr ...
- 洛谷$P$2468 粟粟的书架 $[SDOI2010]$ 主席树
正解:主席树 解题报告: 传送门! 题目大意是说,给定一个矩形,然后每次会给一个,这个大矩形中的一个小矩形,询问从小矩形中最少选多少个数字能满足它们之和大于等于给定数字$x$ 看起来很神的样子,完全不 ...
- bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集
题目:bzoj3673:https://www.lydsy.com/JudgeOnline/problem.php?id=3673 bzoj3674:https://www.lydsy.com/Jud ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
随机推荐
- Spring使用注解方式就行事务管理
使用步骤: 步骤一.在spring配置文件中引入<tx:>命名空间<beans xmlns="http://www.springframework.org/schema/b ...
- NOIP模拟赛14
期望得分:0+100+100=200 实际得分:0+100+100=200 T1 [Ahoi2009]fly 飞行棋 http://www.lydsy.com/JudgeOnline/problem. ...
- 2015/9/21 Python基础(17):绑定和方法调用
绑定和方法调用现在我们需要再次阐述Python中绑定(binding)的概念,它主要与方法调用相关联.方法是类内部定义的函数,这意味着方法是类属性而不是实例属性.其次,方法只有在其所属的类拥有实例时, ...
- Python学习笔记(二十九)ThreadLocal
import threading #创建全局ThreadLocal对象: local_school = threading.local() def process_student(): #获取当前线程 ...
- C11构造函数的改善
1.委托构造函数 委托构造函数就是允许在同一个类中一个构造函数可以调用另一个构造函数,从而在初始化时简化变量的初始化. class CTest { public: int x; int y; int ...
- JavaScript 秘密花园——对象的使用和属性操作
JavaScript 中所有变量都是对象,除了两个例外 null 和 undefined. false.toString(); // 'false' [1, 2, 3].toString(); // ...
- JavaScript定义类的几种方式
提起面向对象我们就能想到类,对象,封装,继承,多态.在<javaScript高级程序设计>(人民邮电出版社,曹力.张欣译.英文名字是:Professional JavaScript for ...
- 您是哪个等级的CSS开发人员?
我们在不断的学习,追求进步与提高,到底学到什么程度了,到底是 不是真的了解CSS,是哪个层次了呢.我们来对照一下. 第0级:CSS?那不是一个多人射击游戏吗? CSS? Isn't that a m ...
- virtual和abstract的区别和联系
壹. 相同 他们有些相似.有些场景用哪个都行! 1. 修饰父类.让子类重写 virtual和abstract都是用来修饰父类的,通过覆盖父类的定义,让子类重新定义. 2. 都用必须public 如 ...
- 用VIM查看编辑二进制文件
用VIM查看编辑二进制文件 vim可以很方便地编辑二进制文件,个人认为它比emacs的二进制编辑方式更好用.vim中二进制文件的编辑是先通过外部程序xxd来把文件dump成其二进制的文本形式,然后就可 ...