【題解】Luogu SP8791 DYNALCA - Dynamic LCA
阿新 • • 發佈:2019-01-01
原題傳送門
這題用Link-Cut-Tree解決,Link-Cut-Tree詳解
這道題的難點就在如何求LCA:
我們珂以先對其中一個點進行access操作,然後對另一個點進行access操作,因為LCA到根的邊一定都由第一次access變為實邊了,在之後的這一次access操作的最後一條從虛邊變為實邊的邊的父親就是兩點的LCA
回求LCA後,剩下的幾乎是模板,但有兩種做法
1.建立虛擬點n+1,保證一直是一顆有n+1個點的樹,寫起來比較無腦(lct部分珂以複製),常數比較大
#include <bits/stdc++.h> #define N 100005 #define getchar nc using namespace std; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read() { register int x=0,f=1;register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f; } inline void write(register int x) { if(!x)putchar('0');if(x<0)x=-x,putchar('-'); static int sta[20];register int tot=0; while(x)sta[tot++]=x%10,x/=10; while(tot)putchar(sta[--tot]+48); } inline void Swap(register int &a,register int &b) { a^=b^=a^=b; } struct Link_Cut_Tree{ int c[N][2],fa[N],top,q[N],rev[N]; inline void pushdown(register int x) { if(rev[x]) { register int l=c[x][0],r=c[x][1]; rev[l]^=1,rev[r]^=1,rev[x]^=1; Swap(c[x][0],c[x][1]); } } inline bool isroot(register int x) { return c[fa[x]][0]!=x&&c[fa[x]][1]!=x; } inline void rotate(register int x) { int y=fa[x],z=fa[y],l,r; l=c[y][0]==x?0:1; r=l^1; if(!isroot(y)) c[z][c[z][0]==y?0:1]=x; fa[x]=z; fa[y]=x; fa[c[x][r]]=y; c[y][l]=c[x][r]; c[x][r]=y; } inline void splay(register int x) { top=1; q[top]=x; for(register int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i]; for(register int i=top;i;--i) pushdown(q[i]); while(!isroot(x)) { int y=fa[x],z=fa[y]; if(!isroot(y)) rotate((c[y][0]==x)^(c[z][0]==y)?(x):(y)); rotate(x); } } inline void access(register int x) { for(register int t=0;x;t=x,x=fa[x]) { splay(x); c[x][1]=t; } } inline void makeroot(register int x) { access(x); splay(x); rev[x]^=1; } inline void split(register int x,register int y) { makeroot(x); access(y); splay(y); } inline void cut(register int x,register int y) { split(x,y); c[y][0]=0; fa[x]=0; } inline void link(register int x,register int y) { makeroot(x); fa[x]=y; } inline int LCA(register int x,register int y) { access(x); int t; for(t=0;y;t=y,y=fa[y]) { splay(y); c[y][1]=t; } return t; } }T; int fa[N]; int main() { int n=read(),m=read(); for(register int i=1;i<=n;++i) T.link(i,n+1),fa[i]=n+1; while(m--) { char c=getchar(); while(c!='k'&&c!='t'&&c!='a') c=getchar(); if(c=='k') { int x=read(),y=read(); T.cut(x,fa[x]); fa[x]=y; T.link(x,y); } else if(c=='t') { int x=read(); T.cut(x,fa[x]); fa[x]=n+1; T.link(x,n+1); } else { int x=read(),y=read(); T.makeroot(n+1); write(T.LCA(x,y)),puts(""); } } return 0; }
2.按照題目加邊,刪邊(常數小,容易寫錯)
注意:cut和LCA操作是不能使用makeroot操作的,因為makeroot本身會修改樹上的LCA關係,當然link操作使用makeroot是沒有關係的
#include <bits/stdc++.h> #define N 100005 #define getchar nc using namespace std; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read() { register int x=0,f=1;register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f; } inline void write(register int x) { if(!x)putchar('0');if(x<0)x=-x,putchar('-'); static int sta[20];register int tot=0; while(x)sta[tot++]=x%10,x/=10; while(tot)putchar(sta[--tot]+48); } inline void Swap(register int &a,register int &b) { a^=b^=a^=b; } struct Link_Cut_Tree{ int c[N][2],fa[N],top,q[N],rev[N]; inline void pushdown(register int x) { if(rev[x]) { register int l=c[x][0],r=c[x][1]; rev[l]^=1,rev[r]^=1,rev[x]^=1; Swap(c[x][0],c[x][1]); } } inline bool isroot(register int x) { return c[fa[x]][0]!=x&&c[fa[x]][1]!=x; } inline void rotate(register int x) { int y=fa[x],z=fa[y],l,r; l=c[y][0]==x?0:1; r=l^1; if(!isroot(y)) c[z][c[z][0]==y?0:1]=x; fa[x]=z; fa[y]=x; fa[c[x][r]]=y; c[y][l]=c[x][r]; c[x][r]=y; } inline void splay(register int x) { top=1; q[top]=x; for(register int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i]; for(register int i=top;i;--i) pushdown(q[i]); while(!isroot(x)) { int y=fa[x],z=fa[y]; if(!isroot(y)) rotate((c[y][0]==x)^(c[z][0]==y)?(x):(y)); rotate(x); } } inline void access(register int x) { for(register int t=0;x;t=x,x=fa[x]) { splay(x); c[x][1]=t; } } inline void makeroot(register int x) { access(x); splay(x); rev[x]^=1; } inline void cut(register int x) { access(x); splay(x); fa[c[x][0]]=0; c[x][0]=0; } inline void link(register int x,register int y) { makeroot(x); fa[x]=y; } inline int LCA(register int x,register int y) { access(x); int t; for(t=0;y;t=y,y=fa[y]) { splay(y); c[y][1]=t; } return t; } }T; int fa[N]; int main() { int n=read(),m=read(); while(m--) { char c=getchar(); while(c!='k'&&c!='t'&&c!='a') c=getchar(); if(c=='k') { int x=read(),y=read(); T.link(x,y); } else if(c=='t') { int x=read(); T.cut(x); } else { int x=read(),y=read(); write(T.LCA(x,y)),puts(""); } } return 0; }