bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集
题目:bzoj3673:https://www.lydsy.com/JudgeOnline/problem.php?id=3673
bzoj3674:https://www.lydsy.com/JudgeOnline/problem.php?id=3674
洛谷P3402:https://www.luogu.org/problemnew/show/P3402
可持久化并查集!就是用主席树模拟并查集,真美!
路径压缩版:和并查集的相似之处想想感觉好妙;
但复杂度似乎有点不科学,bzoj 的两道题都能过,但洛谷上的模板过不了;
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=2e4+,maxm=3e6+;
//int const maxn=2e5+5,maxm=1e7+5;
int n,m,f[maxm],ls[maxm],rs[maxm],rt[maxn],cnt,ans;
void build(int &x,int l,int r)
{
x=++cnt;
if(l==r){f[x]=l; return;}
int mid=((l+r)>>);
build(ls[x],l,mid); build(rs[x],mid+,r);
}
void insert(int x,int &y,int l,int r,int pos,int val)
{
y=++cnt;
if(l==r){f[y]=val; return;}//不是f[pos]
int mid=((l+r)>>);
ls[y]=ls[x]; rs[y]=rs[x];
if(pos<=mid)insert(ls[x],ls[y],l,mid,pos,val);
else insert(rs[x],rs[y],mid+,r,pos,val);
}
int query(int x,int l,int r,int pos)
{
if(l==r)return f[x];
int mid=((l+r)>>);
if(pos<=mid)return query(ls[x],l,mid,pos);
else return query(rs[x],mid+,r,pos);
}
int find(int &root,int pos)
{
int tmp=query(root,,n,pos);
if(tmp==pos)return pos;
int ret=find(root,tmp);
insert(root,root,,n,pos,ret);//路径压缩,修改root
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
build(rt[],,n);
for(int i=,op,k,x,y;i<=m;i++)
{
scanf("%d",&op);
if(op==)
{
scanf("%d%d",&x,&y);
// x^=ans; y^=ans;
int fx=find(rt[i-],x),fy=find(rt[i-],y);
if(fx==fy)rt[i]=rt[i-];
else insert(rt[i-],rt[i],,n,fx,fy);
}
if(op==)
{
scanf("%d",&k);
// k^=ans;
rt[i]=rt[k];
}
if(op==)
{
scanf("%d%d",&x,&y);
// x^=ans; y^=ans;
int fx=find(rt[i-],x),fy=find(rt[i-],y);
if(fx==fy)ans=,printf("1\n");
else ans=,printf("0\n");
rt[i]=rt[i-];
}
}
return ;
}
按秩合并版:复杂度科学,写起来也很简洁,洛谷模板能过;
感觉数据结构写好了模板摆在那儿什么都能干,很方便啊。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=2e5+,maxm=1e7+;
int n,m,f[maxm],ls[maxm],rs[maxm],dep[maxm],rt[maxn],cnt,ans;
void build(int &x,int l,int r)
{
x=++cnt;
if(l==r){f[x]=l; dep[x]=; return;}
int mid=((l+r)>>);
build(ls[x],l,mid); build(rs[x],mid+,r);
}
void insert(int x,int &y,int l,int r,int pos,int val)
{
y=++cnt;
if(l==r){f[y]=val; dep[y]=dep[x]; return;}
int mid=((l+r)>>);
ls[y]=ls[x]; rs[y]=rs[x];
if(pos<=mid)insert(ls[x],ls[y],l,mid,pos,val);
else insert(rs[x],rs[y],mid+,r,pos,val);
}
void add(int x,int &y,int l,int r,int val)
{
y=++cnt;
if(l==r){f[y]=val; dep[y]=dep[x]+; return;}
int mid=((l+r)>>);
ls[y]=ls[x]; rs[y]=rs[x];
if(val<=mid)add(ls[x],ls[y],l,mid,val);
else add(rs[x],rs[y],mid+,r,val);
}
int query(int x,int l,int r,int pos)
{
if(l==r)return x;
int mid=((l+r)>>);
if(pos<=mid)return query(ls[x],l,mid,pos);
else return query(rs[x],mid+,r,pos);
}
int find(int &root,int pos)
{
int tmp=query(root,,n,pos);
if(f[tmp]==pos)return tmp;
return find(root,f[tmp]);
}
int main()
{
scanf("%d%d",&n,&m);
build(rt[],,n);
for(int i=,op,k,x,y;i<=m;i++)
{
scanf("%d",&op);
if(op==)
{
scanf("%d%d",&x,&y);
int fx=find(rt[i-],x),fy=find(rt[i-],y);
if(f[fx]==f[fy]){rt[i]=rt[i-]; continue;}
if(dep[fx]>dep[fy])swap(fx,fy);
insert(rt[i-],rt[i],,n,f[fx],f[fy]);
if(dep[fx]==dep[fy])add(rt[i],rt[i],,n,f[fy]);//最大深度相等则合并后dep+1
}
if(op==)
{
scanf("%d",&k);
rt[i]=rt[k];
}
if(op==)
{
scanf("%d%d",&x,&y);
int fx=find(rt[i-],x),fy=find(rt[i-],y);
if(fx==fy)ans=,printf("1\n");
else ans=,printf("0\n");
rt[i]=rt[i-];
}
}
return ;
}
bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集的更多相关文章
- 洛谷P3402 可持久化并查集
n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 说是可持久化并查集,实际上是 ...
- BZOJ3673 & BZOJ3674 & 洛谷3402:可持久化并查集——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3673 https://www.lydsy.com/JudgeOnline/problem.php? ...
- P3402 可持久化并查集
P3402 通过主席树维护不同版本的并查集,注意要采用按秩合并的方式,路径压缩可能会爆. 1 #include <bits/stdc++.h> 2 using namespace std; ...
- 洛谷 3295 [SCOI2016]萌萌哒——并查集优化连边
题目:https://www.luogu.org/problemnew/show/P3295 当要连的边形如 “一段区间内都是 i 向 i+L 连边” 的时候,用并查集优化连边. 在连边的时候,如果要 ...
- 洛谷P2024 食物链 [NOI2001] 并查集
正解:并查集 解题报告: 传送门(咕了! 其实没有很难(虽然我是交了三发才过的QAQ 但是一来好久没打并查集了恢复一下智力 二来看着智推里唯一一个蓝就很不爽(,,,虽然做了这题之后又补上了个蓝题QAQ ...
- 洛谷P1197 [JSOI2008] 星球大战 [并查集]
题目传送门 星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这 ...
- 洛谷 P1551 亲戚(并查集模板)
嗯... 题目链接:https://www.luogu.org/problemnew/show/P1551 思路: 很显然地我们会发现,这是一道并查集的模板题,并且是考察了并查集中的”并“和”查“的操 ...
- 洛谷P1111修复公路并查集改
看了他们的题解感觉很震惊,为什么要用kruskal,这题要用到最小生成树吗??? 38行短短的程序就可以了,我觉得学习不是一种套用,套自己学的,而且题解很大一部分都是kruskal. 个人认为自己的程 ...
- 洛谷P1525关押罪犯——并查集
题目:https://www.luogu.org/problemnew/show/P1525 并查集+贪心,从大到小排序,将二人分在不同房间,找到第一个不满足的即为答案. 代码如下: #include ...
随机推荐
- Linux 查询PID和端口号
https://www.cnblogs.com/understander/p/5546458.html
- Django中 基于form的注册,基于ajax的登录
1 form.py中写register的的form组件 from django import forms class Register(forms.Form): # 注册的form username ...
- vsftpd:500OOPS:vsftpd:refusingtorunwithwritablerootinsidechroot()错误的解决方法
当我们限定了用户不能跳出其主目录之后,使用该用户登录FTP时往往会遇到这个错误: 500 OOPS: vsftpd: refusing to run with writable root inside ...
- linux虚拟主机的三种方法
虚拟主机虚拟主机是将一台(或者一组)服务器的资源(系统资源.网络带宽.存储空间等)按照一定的比例分割成若干相对独立的“小主机”的技术.每一台这样的“小主机”在功能上都可以实现WWW.FTP.Mail等 ...
- JavaScript day3(运算符)
运算符(operator) 基本运算符: 算术运算符用于执行变量之间的算术运算,给定 y=5: 运算符 描述 例子 结果 + 加 x=y+2 x=7 - 减 x=y-2 x=3 * 乘 x=y*2 x ...
- Configuring SSL on Enterprise Manager and the SLB (Release 12.1.0.2 and later)
From: http://docs.oracle.com/html/E24089_42/ha_setup.htm#sthref833 If the SLB is configured to use T ...
- Silverlight之我见——数据批示(2)
接着上一回的话题,继续来研究数据批示特性,先拿简单的RageAttribute来弄弄,接着上次的示例,添加一个Age属性,并加上RangeAttribute. [Range(20,60,ErrorMe ...
- win10如何进入安全模式的几种方法
首先,说一下安全模式的作用: 安全模式, 用途有很多,常见的作用有以下几点 1. 电脑可能由于安装了某些驱动或者软件,不兼容导致电脑启动不了,可以进入安全模式卸载 2. 电脑中病毒之后,可以进入安全模 ...
- PAT 1101 Quick Sort
There is a classical process named partition in the famous quick sort algorithm. In this process we ...
- Spring Boot的常见配置项解析
1.spring-boot-starter-parent:springboot官方推荐的maven管理工具,最简单的做法就是继承它. spring-boot-starter-parent包含了以下信息 ...