第一种是离线的Tarjan算法
#include<cstdio> using namespace std; int rd(){ int x=0,fl=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-'){fl=-1;}ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return fl*x; } int n,m,s,x,y,num1,num2; int f[500001],dis[500001],a[500001][3],hd1[500001],hd2[500001]; bool vis[500001]; struct star{int nt,to,ds;}e[1000001],e2[1000001]; void add1(int from,int to){ e[++num1].nt=hd1[from]; e[num1].to=to; hd1[from]=num1; } void add2(int from,int to,int ds){ e2[++num2].nt=hd2[from]; e2[num2].to=to; e2[num2].ds=ds; hd2[from]=num2; } int find(int x){ if(f[x]!=x) f[x]=find(f[x]); return f[x]; } void un(int x,int y){ int ra=find(x),rb=find(y); f[ra]=rb; } void tarjan(int x){ vis[x]=1; for(int i=hd2[x];i;i=e2[i].nt){ int to=e2[i].to,dis=e2[i].ds; if(vis[to]) a[dis][2]=find(to); } for(int i=hd1[x];i;i=e[i].nt){ int to=e[i].to; if(!vis[to]){ tarjan(to); un(to,x); } } } int main(){ n=rd();m=rd();s=rd(); for(int i=1;i<n;i++){ x=rd();y=rd(); add1(x,y);add1(y,x); } for(int i=1;i<=m;i++){ x=rd();y=rd(); a[i][0]=x;a[i][1]=y; add2(x,y,i);add2(y,x,i); } for(int i=1;i<=n;i++)f[i]=i; tarjan(s); for(int i=1;i<=m;i++) printf("%d ",a[i][2]); return 0; }
这个代码跑的飞快但是不太好理解。。
还有一种用倍增的思想
#include<iostream> #include<cstdio> using namespace std; int rd(){ int x=0,fl=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-'){fl=-1;}ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return fl*x; } int n,m,x,y,s,num=0,hd[500100],dep[500100],f[500100][21]; struct star{int nt,to;}e[1000100]; void add(int fm,int to){e[++num].to=to;e[num].nt=hd[fm];hd[fm]=num;} void dfs(int x,int fa){ dep[x]=dep[fa]+1; for(int i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1]; for(int i=hd[x];i;i=e[i].nt) { int to=e[i].to; if(to==fa)continue; f[to][0]=x; dfs(to,x); } } int lca(int u,int v){ if(dep[u]<dep[v])swap(u,v); for(int i=20;i>=0;i--){ if(dep[f[u][i]]>=dep[v]) u=f[u][i]; if(u==v)return u; } for(int i=20;i>=0;i--) if(f[u][i]!=f[v][i]){ u=f[u][i];v=f[v][i]; } return f[u][0]; } void print(int x){ if(x<0){putchar('-');x=-x;} if(x>9)print(x/10); putchar(x%10+'0'); } int main(){ n=rd();m=rd();s=rd(); for(int i=1;i<n;i++){ x=rd();y=rd(); add(x,y);add(y,x); } dfs(s,0); for(int i=1;i<=m;i++){ x=rd();y=rd(); print(lca(x,y)); putchar(' '); } return 0; }
emmm....这种比较好理解但是跑的有点慢...
其实还有一种bfs版的玄学算法也安利一下