最近公共祖先(LCA)
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 const int MAXN=500010; 6 7 int n,m,s; 8 int fa[MAXN][20]; //结点i往上2^j的祖先 9 int dep[MAXN]; //每个结点的深度 10 11 struct Edge 12 { 13 int next,to; 14 }e[MAXN*2]; 15 int head[MAXN],cnt=0; 16 void addEdge(int x,int y) 17 { 18 cnt++; 19 e[cnt].next=head[x]; 20 e[cnt].to=y; 21 head[x]=cnt; 22 return; 23 } 24 25 void dfs(int u,int f) 26 { 27 fa[u][0]=f; 28 dep[u]=dep[f]+1; 29 for (int i=1;(1<<i)<=dep[u];i++) 30 { 31 fa[u][i]=fa[fa[u][i-1]][i-1]; //倍增求祖先 32 } 33 for (int i=head[u];i!=0;i=e[i].next) 34 { 35 int v=e[i].to; 36 if (v!=f) dfs(v,u); //因双向建边,注意判断v是否为fa,否则会死循环 37 } 38 return; 39 } 40 41 int lca(int x,int y) 42 { 43 if (dep[x]<dep[y]) swap(x,y); //保证开始时 x深度>y 44 for (int i=19;i>=0;i--) 45 { 46 if (dep[fa[x][i]]>=dep[y]) x=fa[x][i]; //将x上升到与y同一深度 47 } 48 if (x==y) return x; //特判,y是x的祖先 49 for (int i=19;i>=0;i--) 50 { 51 if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; //将x y上升到最近公共祖先的深度+1处,即最远的非公共祖先处 52 } 53 return fa[x][0]; //此时,最近公共祖先为当前结点的父结点 54 } 55 56 int main() 57 { 58 scanf("%d%d%d",&n,&m,&s); 59 for (int i=1;i<n;i++) 60 { 61 int u,v; 62 scanf("%d%d",&u,&v); 63 addEdge(u,v); 64 addEdge(v,u); 65 } 66 67 dfs(s,0); 68 69 while (m--) 70 { 71 int x,y; 72 scanf("%d%d",&x,&y); 73 printf("%d\n",lca(x,y)); //求最近公共祖先 74 } 75 76 return 0; 77 }