各種LCA——最近公共祖先
阿新 • • 發佈:2020-12-01
模板題目
倍增
#include<cmath> #include<cstdio> #include<cstring> const int N=500005; int f[N<<1][20],dep[N],lg,ch,cnt,he[N],to[N<<1],ne[N<<1]; inline void rl(int &x){ x=0;while((ch=getchar())<48||57<ch); for(;47<ch&&ch<58;ch=getchar())x=x*10+(ch^48); } #define add(u,v) {to[++cnt]=v;ne[cnt]=he[u];he[u]=cnt;} typedef const int& ct; inline int min(ct a,ct b){return a<b?a:b;} void dfs(ct u,ct d){ dep[u]=d; for(int j=1;j<=lg;++j)f[u][j]=f[f[u][j-1]][j-1]; for(int i=he[u];i;i=ne[i]) if(to[i]!=f[u][0])f[to[i]][0]=u,dfs(to[i],d+1); } inline int lca(int x,int y){ if(int t=1&&dep[x]<dep[y])t=x,x=y,y=t; for(int i=lg;i>=0;--i) if(dep[f[x][i]]>=dep[y])x=f[x][i]; if(x==y)return y; for(int i=lg;i>=0;--i) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int main(){ int n,m,s,x,y; rl(n);rl(m);rl(s);lg=(int)log2(n)+1; for(int i=1;i<n;++i){ rl(x);rl(y);add(x,y);add(y,x); } dfs(s,1); while(m--){ rl(x);rl(y); printf("%d\n",lca(x,y)); } return 0; }
尤拉序+st表
#include<cmath> #include<cstdio> #include<cstring> const int N=500005; int st[N<<1][22],el[N<<1],id[N<<1][20],ch,cnt,he[N],to[N<<1],ne[N<<1];//log2(2e5)<18 inline void rl(int &x){ x=0;while((ch=getchar())<48||57<ch); for(;47<ch&&ch<58;ch=getchar())x=x*10+(ch^48); } #define add(u,v) {to[++cnt]=v;ne[cnt]=he[u];he[u]=cnt;} typedef const int& ct; inline int min(ct a,ct b){return a<b?a:b;} void euler(ct u,ct dep){ st[el[u]=++cnt][0]=dep;id[cnt][0]=u; for(int i=he[u];i;i=ne[i])if(!el[to[i]]){ euler(to[i],dep+1); st[++cnt][0]=dep;id[cnt][0]=u; } } inline int lca(ct a,ct b){ int x=el[a],y=el[b];if(x>y){int t=y;y=x;x=t;}int le=log2(y-x+1); //printf("x%d y%d le%d\n",x,y,le); return st[x][le]<st[y-(1<<le)+1][le]? id[x][le]:id[y-(1<<le)+1][le]; } #define dbg1() {for(int i=0;i<n2;++i){printf("line%d:\t",i);for(int j=0;j<=8;++j)printf("%d ",id[i][j]);putchar(10);}} #define dbg2() {for(int i=1;i<=n;++i)printf("%d:\t%d\n",i,el[i]);} int main(){ int n,m,s,x,y,lg,n2; rl(n);rl(m);rl(s); n2=n<<1;lg=20; for(int i=0;i<n2;++i) memset(st[i],63,lg+1<<2),memset(id[i],63,lg+1<<2); for(int i=1;i<n;++i){ rl(x);rl(y);add(x,y);add(y,x); } cnt=0;euler(s,1); //for(int i=1;i<n2;++i)printf("%d ",id[i][0]);putchar(10); for(int j=1,i,maxx;j<=lg;++j){ maxx=n2-(1<<j);//間隔 -一個 for(i=1;i<=maxx;++i) if(st[i][j-1]<st[i+(1<<j-1)][j-1]) st[i][j]=st[i][j-1],id[i][j]=id[i][j-1]; else st[i][j]=st[i+(1<<j-1)][j-1], id[i][j]=id[i+(1<<j-1)][j-1]; } //dbg1();dbg2(); while(m--){ rl(x);rl(y); printf("%d\n",lca(x,y)); } return 0; }
樹鏈剖分(第一次寫了14min,我太菜了)
#include<cstdio> typedef const int ct; ct N=1000006; inline int rl(){ int x=0,ch;while((ch=getchar())<48||57<ch); for(;47<ch&&ch<58;ch=getchar())x=x*10+(ch^48); return x; } int to[N],ne[N],he[N],size[N],fa[N],dep[N],son[N],id[N],cnt,top[N]; int dfs1(ct& u,ct& f){ int size=1; for(int i=he[u],v,ss,ms=-1;i;i=ne[i])if((v=to[i])!=f){ dep[v]=dep[u]+1; size+=ss=dfs1(v,fa[v]=u); if(ss>ms)son[u]=v,ms=ss; } return size; } void dfs2(ct& u,ct& topf){ id[u]=++cnt; if(son[u])dfs2(son[u],top[son[u]]=topf); for(int i=he[u],v;i;i=ne[i]) if((v=to[i])!=fa[u]&&v!=son[u])dfs2(v,top[v]=v); } inline int lca(int x,int y){ int t; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])t=x,x=y,y=t; x=fa[top[x]]; } //二者同一重鏈 return dep[x]<dep[y]?x:y; } int main(){ int n=rl(),m=rl(),s=rl(); for(int i=1,x,y,cnt=0;i<n;++i){ to[++cnt]=y=rl();ne[cnt]=he[x=rl()];he[x]=cnt; to[++cnt]=x;ne[cnt]=he[y];he[y]=cnt; } dep[s]=1; dfs1(s,fa[s]=-1); dfs2(s,top[s]=s); while(m--)printf("%d\n",lca(rl(),rl())); return 0; }