题目: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 可持久化并查集的更多相关文章

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

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

  2. BZOJ3673 & BZOJ3674 & 洛谷3402:可持久化并查集——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3673 https://www.lydsy.com/JudgeOnline/problem.php? ...

  3. P3402 可持久化并查集

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. JS高级——Function原型链

    基本概念 1.函数可以通过Function new出来,那么Function可以被称作构造函数,被new出来的函数可以被称为一个对象 2.Function既然是构造函数,那么肯定也有原型,它的原型是一 ...

  2. JS——锚点的运用

    锚点的两种形式: 1.<a href="#a">点击到锚点</a> 2.window.location.hash = "#a"; 最后都 ...

  3. 如何在Linuxt系统下运行maven项目

    如何在Linuxt系统下运行maven项目 我们知道现在利用MAVEN来管理JAVA项目是非常常见的.比如公司一般都有一个自己的MAVEN仓库,通过MAVEN仓库来解决我们的项目依赖,更加方便的构建项 ...

  4. js 攻坚克难

    new new : 官方解释: 如果在一个函数前面带上new来调用,那么背地里将会创建一个连接到该函数的prototype的成员的新对象,同时this会被绑定到哪个新对象上: new 是用来创建对象的 ...

  5. Python 之re正则表达式

  6. Windows如何正确的修改administrator用户名

    无论是服务器还是电脑.修改默认的administrator的用户总是好的.话不多少.直接上图 1.win+r  输入:gpedit.msc 2.按照我下图的圈圈找到重命名系统管理员账户并自定义 3.重 ...

  7. 回溯法、DFS

    回溯法 为了求得问题的解,先选择某一种可能情况向前探索,在探索过程中,一旦发现原来的选择是错误的,就退回上一步重新选择条件,继续向前探索,如此反复进行,直至得到解或证明无解. DFS DFS模板 vo ...

  8. Win32 线程同步

    Win32 线程同步 ## Win32线程同步 ### 1. 原子锁 ### 2. 临界区 {全局变量} CRITICAL_SECTION CS = {0}; // 定义并初始化临界区结构体变量 {线 ...

  9. java 常见问题

    1.Cannot convert value '0000-00-00 00:00:00' from column 1 to TIMESTAMP 2.怎么解决BigDecimal里面无限循环小数的问题啊 ...

  10. SVG格式图片转成HTML中SVG的Path路径

    AI图标制作完成之后,保存的svg文件包含许多AI的信息,如果要在HTML中使用,我们需要在svg文件中提取/修改信息,重新保存. 1.在AI中已经完成图标,要保存SVG文件,点击“文件(File)” ...