首页 > 代码库 > BZOJ 3673 可持久化并查集 by zky 可持久化并查集
BZOJ 3673 可持久化并查集 by zky 可持久化并查集
题目大意:给定n个集合,提供三种操作:
1.合并a,b所在集合
2.回到第k次操作之后的状态
3.询问a,b是否在同一集合
可持久化并查集0.0 实现方式是用可持久化线段树实现可持久化数组维护可持久化并查集。。。
至于可持久化数组,每条路径上只有叶节点的位置的num域是有意义的,感觉无比浪费0.0 可是不这样还真没法维护0.0
合并时本来应该按照每个节点的深度之和维护,结果手残懒得写,只用siz维护了0.0
至于路径压缩,写了比不写慢0.0 还是不写了吧
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 200200 using namespace std; struct Tree{ Tree *ls,*rs; int num; }*fa[M],*siz[M],mempool[M*40],*C=mempool; int n,m,now,version[M],tot; inline Tree* New_Node(Tree *_,Tree *__,int ___) { C->ls=_; C->rs=__; C->num=___; return C++; } Tree* Modify(Tree *p,int x,int y,int pos,int val) { int mid=x+y>>1; if(x==y) return New_Node(0x0,0x0,val); if(pos<=mid) return New_Node(Modify(p->ls,x,mid,pos,val),p->rs,0); else return New_Node(p->ls,Modify(p->rs,mid+1,y,pos,val),0); } int Access(Tree *p,int x,int y,int pos) { int mid=x+y>>1; if(x==y) return p->num; if(pos<=mid) return Access(p->ls,x,mid,pos); else return Access(p->rs,mid+1,y,pos); } inline int Find(int x) { int y; while(x) x=Access(fa[now],1,n,y=x); return y; } inline void Unite(int x,int y) { int fx=Find(x),fy=Find(y); if(fx==fy) return; ++tot; int sx=Access(siz[now],1,n,fx); int sy=Access(siz[now],1,n,fy); if( sx<sy ) swap(x,y),swap(fx,fy),swap(sx,sy); fa[tot]=Modify(fa[now],1,n,fy,fx); siz[tot]=Modify(siz[now],1,n,fx,sx+sy); now=tot; } inline bool Query(int x,int y) { return Find(x)==Find(y); } int main() { int i,p,x,y; cin>>n>>m; fa[0]=New_Node(C,C,0); siz[0]=New_Node(C,C,1); for(i=1;i<=m;i++) { scanf("%d",&p); switch(p) { case 1:scanf("%d%d",&x,&y),Unite(x,y);break; case 2:scanf("%d",&x),now=version[x];break; case 3:scanf("%d%d",&x,&y),printf("%d\n",Query(x,y));break; } version[i]=now; } }
BZOJ 3673 可持久化并查集 by zky 可持久化并查集
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。