bzoj3674: 可持久化并查集加强版
主席树。
我分不清主席树和可持久化线段树。。
用主席树记录历史版本。
然后每个节点保存一个深度,代表以自己为根的树的深度。
合并时将深度小的树合进深度大的树。
3673也是一样的,不过那道题不强制在线。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 200000 + 10; const int maxm = 5000000 + 10; int n,m,vid; int root[maxn],lc[maxm],rc[maxm],v[maxm],dep[maxm]; void build(int &x,int l,int r) { if(!x) x=++vid; if(l==r) {v[x]=l;return;} int mid=(l+r)>>1; build(lc[x],l,mid); build(rc[x],mid+1,r); } void modify(int &x,int y,int l,int r,int pos,int val) { x=++vid; if(l==r) {v[x]=val; dep[x]=dep[y]; return;} lc[x]=lc[y]; rc[x]=rc[y]; int mid=(l+r)>>1; if(pos<=mid) modify(lc[x],lc[y],l,mid,pos,val); else modify(rc[x],rc[y],mid+1,r,pos,val); } int query(int x,int l,int r,int pos) { if(l==r) return x; int mid=(l+r)>>1; if(pos<=mid) return query(lc[x],l,mid,pos); else return query(rc[x],mid+1,r,pos); } void add(int x,int l,int r,int pos) { if(l==r) {dep[x]++; return;} int mid=(l+r)>>1; if(pos<=mid) add(lc[x],l,mid,pos); else return add(rc[x],mid+1,r,pos); } int find(int x,int k) { int p=query(x,1,n,k); if(v[p]==k) return p; else return find(x,v[p]); } int op,a,b; int main() { scanf("%d%d",&n,&m); build(root[0],1,n); for(int i=1;i<=m;i++) { scanf("%d",&op); if(op==1) { root[i]=root[i-1]; scanf("%d%d",&a,&b); int p=find(root[i],a),q=find(root[i],b); if(v[p]==v[q]) continue; if(dep[p]>dep[q]) swap(p,q); modify(root[i],root[i-1],1,n,v[p],v[q]); if(dep[p]==dep[q]) add(root[i],1,n,v[q]); } else if(op==2) { scanf("%d",&a); root[i]=root[a]; } else { root[i]=root[i-1]; scanf("%d%d",&a,&b); int p=find(root[i],a),q=find(root[i],b); printf("%d\n",v[p]==v[q]?1:0); } } return 0; }