[BZOJ3674]可持久化并查集加强版
[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; }