【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集
3673: 可持久化并查集 by zky
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 1878 Solved: 846
[Submit][Status][Discuss]
Description
n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
0<n,m<=2*10^4
Input
Output
Sample Input
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2
Sample Output
0
1
HINT
Source
3674: 可持久化并查集加强版
Time Limit: 15 Sec Memory Limit: 256 MB
Submit: 2367 Solved: 886
[Submit][Status][Discuss]
Description
Description:
自从zkysb出了可持久化并查集后……
hzwer:乱写能AC,暴力踩标程
KuribohG:我不路径压缩就过了!
ndsf:暴力就可以轻松虐!
zky:……
n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为0
0<n,m<=2*10^5
Input
Output
Sample Input
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2
Sample Output
0
1
HINT
Source
Solution
先说离线的一种思路,以前yveh做Codeforces的时候告诉我一道题,与之类似,存在一个状态退回到第多少步,当时是需要线段树维护一个东西,所以可以形成一个树形结构,然后dfs并回溯离线做。
但是这里并不能那么搞,因为并查集不支持删除所以没法回溯,所以只能考虑令并查集的 代表元素数组可持久化
所以本质上都得用可持久化数据结构维护代表元素数组,就无所谓离线在线了。
具体的做法就是建可持久化线段树,每次修改就在线段树上建一个新的链,叶子节点维护的是这个点的代表元素,所以方法很简单就是先初始化建出一棵新的树,然后每次新建一条链即可。
然后这里就剩下一个问题了,就是并查集$find$,为了保证复杂度,我采用了路径压缩但这里发现路径压缩会使树上操作数增多,建很多新的节点,所以常数比较大,然后看了hxy和zyf的代码,发现她们都和hzwer写的一样,采用的按秩合并,不过常数比我还大,不过显而易见 如果不加优化一定会TLE,所以二选一即可,并无太大的差距。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 500010
int N,M,last;
namespace PrTree
{
int sz,lson[MAXN*],rson[MAXN*],root[MAXN],f[MAXN*];
inline void Insert(int l,int r,int &now,int fa,int pos,int val)
{
now=++sz;
if (l==r) {f[now]=val; return;}
int mid=(l+r)>>;
lson[now]=lson[fa],rson[now]=rson[fa];
if (pos<=mid) Insert(l,mid,lson[now],lson[fa],pos,val);
else Insert(mid+,r,rson[now],rson[fa],pos,val);
}
inline int Query(int l,int r,int pos,int now)
{
if (l==r) return f[now];
int mid=(l+r)>>;
if (pos<=mid) return Query(l,mid,pos,lson[now]);
else return Query(mid+,r,pos,rson[now]);
}
inline void BuildTree(int l,int r,int &now)
{
now=++sz;
if (l==r) {f[now]=l; return;}
int mid=(l+r)>>;
BuildTree(l,mid,lson[now]); BuildTree(mid+,r,rson[now]);
}
}using namespace PrTree;
inline int F(int x,int &rt) {int fa; if ((fa=Query(,N,x,rt))==x) return x; else return Insert(,N,rt,rt,x,fa=F(fa,rt)),fa;}
inline void Merge(int x,int y,int &rt) {int fx=F(x,rt),fy=F(y,rt); if (fx!=fy) Insert(,N,rt,rt,fx,fy);}
int main()
{
N=read(),M=read();
BuildTree(,N,root[]);
for (int i=; i<=M; i++)
{
root[i]=root[i-];
int opt=read(),x,y;
switch (opt)
{
case : x=read(),y=read(); x^=last,y^=last; Merge(x,y,root[i]); break;
case : x=read(); x^=last; root[i]=root[x]; break;
case : x=read(),y=read(); x^=last,y^=last; printf("%d\n",last=(F(x,root[i])==F(y,root[i]))); break;
}
}
return ;
}
总体来说写起来还是蛮好写的,就是自己开始手误,在可持久化线段树的时候 左右都下放的lson,然后瞪着屏幕20分钟才看出来...
【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集的更多相关文章
- [WC2005]双面棋盘(线段树+并查集)
线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...
- 【bzoj4399】魔法少女LJJ 并查集+权值线段树合并
题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...
- 2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集)
2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集) https://www.luogu.com.cn/problem/CF811E Ste ...
- bzoj 3673&3674 可持久化并查集&加强版(可持久化线段树+启发式合并)
CCZ在2015年8月25日也就是初三暑假要结束的时候就已经能切这种题了%%% 学习了另一种启发式合并的方法,按秩合并,也就是按树的深度合并,实际上是和按树的大小一个道理,但是感觉(至少在这题上)更好 ...
- BZOJ.3673/3674.可持久化并查集(可持久化线段树 按秩合并/启发式合并)
BZOJ 3673 BZOJ 3674(加强版) 如果每次操作最多只修改一个点的fa[],那么我们可以借助可持久化线段树来O(logn)做到.如果不考虑找fa[]的过程,时空复杂度都是O(logn). ...
- bzoj 3673&3674: 可持久化并查集 by zky
Description n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0& ...
- [bzoj] 3673 3674 可持久化并查集 || 可持久化数组
原题 加强版 题意: 可持久化并查集模板-- 题解: 用可持久化线段树维护一个可持久化数组,来记录每一次操作后的状态. 不能用路径压缩,但是要按置合并,使复杂度保证在O(log) #include&l ...
- [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)
[BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...
- bzoj 2733: [HNOI2012]永无乡【并查集+权值线段树】
bzoj上数组开大会T-- 本来想用set瞎搞的,想了想发现不行 总之就是并查集,每个点开一个动态开点的权值线段树,然后合并的时候把值并在根上,询问的时候找出在根的线段树里找出k小值,看看这个值属于哪 ...
随机推荐
- Android 手机卫士1--实现splash页面
1.minSdkVersion.targetSdkVersion.maxSdkVersion.target API level四个数值到底有什么区别? minSdkVersion, maxSdkVer ...
- echarts学习总结
ECharts学习总结使用步骤1 引入ECharts <script src="echarts.min.js"></script>2 绘制一个简单的图表 为 ...
- react native初步常见问题
首先按照资料一步步搭建环境运行,然后成功了,很激动,可是,安卓就是没这么容易成功,还是太年轻了 could not get batchedbridge, make sure your bundle i ...
- Android中使用Notification实现宽视图通知栏(Notification示例二)
Notification是在你的应用常规界面之外展示的消息.当app让系统发送一个消息的时候,消息首先以图表的形式显示在通知栏.要查看消息的详情需要进入通知抽屉(notificationdrawer) ...
- Razor速记
1.语法 @{ int c=2; } @for(int i=0;i<c;i++) { @i @:@i @:select @:select @i s ...
- UML类图关系全面剖析
UML的类图关系分为: 关联.聚合/组合.依赖.泛化(继承).而其中关联又分为双向关联.单向关联.自身关联:下面就让我们一起来看看这些关系究竟是什么,以及它们的区别在哪里. 1.关联 双向关联:C1- ...
- jQuery解决iframe高度自适应代码
网上查了好多用着都不行,自己搞定了:在包含iframe的页面中加入以下脚本,基本思想是在iframe加载内容后重新设置高度,下面代码尽在IE6中用过,没在其他浏览器中测试. 代码如下: <scr ...
- Quartz2.0以上版本的单机和集群
(一)Quartz单机 1.Quartz简介 Quartz是一个完全由java编写的开源作业调度框架,能实现业务的定时调度.Quartz主要有三个核心调度器.任务和触发器: ①任务-JobDetail ...
- 跳入linux的第一个坑-因为安装Ubuntu导致的硬盘被误格的恢复.(记TestDisk使用记录)
不看废话,直接跳到操作说明 前几日心血来潮想把家中的旧笔记本换成Linux操作系统,算是在业余生活中正式投入Linux的怀抱.说干就干,发行版选择了Ubuntu,下载了Ubuntu16.04的ISO, ...
- mongodb 性能篇
一. 索引及其优化 索引的概述 数据库的索引好比是一本书前面的目录,能加快数据查询的速度. 适当的地方增加索引,不合理的地方删除次优索引,能优化性能较差的应用. 索引的操作 基础索引:db.ken. ...