隐藏页面特效

[BZOJ3674]可持久化并查集加强版

1|0[BZOJ3674]可持久化并查集加强版


★★★   输入文件:bzoj_3974.in   输出文件:bzoj_3974.out   简单对比
时间限制:3 s   内存限制:256 MB

 

DescriptionDescription:

自从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

InputOutputSample Input

5 6

1 1 2

3 1 2

2 1

3 0 3

2 1

3 1 2

Sample Output

1

0

1

by zky

/* 可持久化线段树+启发式合并.(引自yjy) 可持久化线段树维护当前状态下集合的关系和秩的信息. 所谓的秩就是以该元素为代表元的所有元素中的最大深度. 然后按秩合并的目的是为了降常. 每个叶节点维护一颗线段树 合并的时候在权值线段树的子节点加一个数, 相当于连了一条边 表示有关系存在. 要先查询要将合并两个元素的父亲所在位置. 显然只有在两个集合秩相同时才更新秩. */ #include<cstdio> #include<iostream> using namespace std; const int N=2e5+5,Z=N*20; int n,m; int sz,root[N],ls[Z],rs[Z],dep[Z],fax[Z]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void build(int &k,int l,int r){ k=++sz; if(l==r){ fax[k]=l;return ; } int mid=l+r>>1; build(ls[k],l,mid); build(rs[k],mid+1,r); } int find_pos(int &k,int l,int r,int x){ if(l==r) return k; int mid=l+r>>1; if(x<=mid) return find_pos(ls[k],l,mid,x); else return find_pos(rs[k],mid+1,r,x); } int get_fa(int &k,int x){//非路径压缩 int p=find_pos(k,1,n,x); if(fax[p]==x) return p; else return get_fa(k,fax[p]); } void insert(int &k,int last,int l,int r,int x,int y){ k=++sz; if(l==r){fax[k]=y;dep[k]=dep[last];return ;} ls[k]=ls[last]; rs[k]=rs[last]; int mid=l+r>>1; if(x<=mid) insert(ls[k],ls[last],l,mid,x,y); else insert(rs[k],rs[last],mid+1,r,x,y); } void update(int &k,int l,int r,int v){ if(l==r){dep[k]++;return ;} int mid=l+r>>1; if(v<=mid) update(ls[k],l,mid,v); else update(rs[k],mid+1,r,v); } void merge(int l1,int l2,int i){ if(dep[l1]>dep[l2]) swap(l1,l2); insert(root[i],root[i-1],1,n,fax[l1],fax[l2]); if(dep[l1]==dep[l2]) update(root[i],1,n,fax[l2]); } int main(){ freopen("bzoj_3974.in","r",stdin); freopen("bzoj_3974.out","w",stdout); n=read();m=read(); build(root[0],1,n); for(int i=1,opt,x,y,l1,l2,ans=0;i<=m;i++){ opt=read();x=read()^ans;if(opt&1) y=read()^ans; root[i]=root[opt&1?i-1:x]; if(opt==1){ l1=get_fa(root[i],x); l2=get_fa(root[i],y); if(l1!=l2) merge(l1,l2,i); } if(opt==3){ l1=get_fa(root[i],x); l2=get_fa(root[i],y); ans=(l1==l2); printf("%d\n",ans); } } return 0; }

 


__EOF__

本文作者shenben
本文链接https://www.cnblogs.com/shenben/p/6472792.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   神犇(shenben)  阅读(730)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示