BZOJ3674:可持久化並查集加強版
阿新 • • 發佈:2018-11-16
淺談主席樹:https://www.cnblogs.com/AKMer/p/9956734.html
題目傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=3674
因為要支援歷史操作,所以我們用可持久化線段樹來維護並查集的祖先陣列。
因為要路徑壓縮,所以每個點會被建\(k*logn\)次,\(k\)未知,但是絕對不大。
時間複雜度:\(O(mklogn)\)
空間複雜度:\(O(mklogn)\)
程式碼如下:
#include <cstdio> using namespace std; const int maxn=2e5+5; int rt[maxn]; int n,m,lstans; int read() { int x=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0'; return x*f; } struct tree_node { int fa,ls,rs; }; struct Chairman_tree { int tot; tree_node tree[maxn*40]; void build(int &now,int l,int r) { now=++tot; if(l==r) {tree[now].fa=l;return;} int mid=(l+r)>>1; build(tree[now].ls,l,mid); build(tree[now].rs,mid+1,r); } int query(int now,int l,int r,int pos) { if(l==r)return tree[now].fa; int mid=(l+r)>>1; if(pos<=mid)return query(tree[now].ls,l,mid,pos); return query(tree[now].rs,mid+1,r,pos); } void change(int lst,int &now,int l,int r,int pos,int v) { now=++tot;tree[now]=tree[lst]; if(l==r) {tree[now].fa=v;return;} int mid=(l+r)>>1; if(pos<=mid)change(tree[lst].ls,tree[now].ls,l,mid,pos,v); else change(tree[lst].rs,tree[now].rs,mid+1,r,pos,v); } }T; int find(int &root,int x) { int f=T.query(root,1,n,x); if(f==x)return x; int res=find(root,f); T.change(root,root,1,n,x,res);//路徑壓縮相當於在上一版本主席樹上面更改祖先陣列 return res; } int main() { n=read(),m=read(); T.build(rt[0],1,n); for(int i=1;i<=m;i++) { int opt=read(); if(opt==1) { int a=read()^lstans,b=read()^lstans; int p=find(rt[i-1],a),q=find(rt[i-1],b); if(p==q)rt[i]=rt[i-1];//如果不需要合併就不合並 else T.change(rt[i-1],rt[i],1,n,p,q); } else if(opt==2) { int t=read()^lstans; rt[i]=rt[t]; } else if(opt==3) { int a=read()^lstans,b=read()^lstans; int p=find(rt[i-1],a),q=find(rt[i-1],b); if(p==q)lstans=1; else lstans=0; rt[i]=rt[i-1];//詢問也算操作 printf("%d\n",lstans); } } return 0; }