题意
给出一个树,有m次询问,求出这两个节点的最近公共祖先。
思路
用倍增的方法。先让两个节点的深度相同,然后每次一起跳,就能得到答案了。
代码
#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int to,next;
}e[500001<<1];
int n,m,s,tot,d[500001],head[500001],t,f[500001][20];
inline void add(int u,int v) {e[++tot].to=v;e[tot].next=head[u];head[u]=tot;}
inline void bfs(int s)//求深度 初始化f
{
int x,y;
queue<int> q;
d[s]=1;
q.push(s);
while (q.size())
{
x=q.front();q.pop();
for (int i=head[x];i;i=e[i].next)
{
y=e[i].to;
if (d[y]) continue;
d[y]=d[x]+1;
f[y][0]=x;
for (int j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1];
q.push(y);
}
}
}
inline int LCA(int x,int y)
{
if (d[x]>d[y]) swap(x,y);
for (int i=t;i>=0;i--)
if (d[f[y][i]]>=d[x]) y=f[y][i];//调整深度
if (x==y) return x;//如果已经相等了就说明其中一个就是答案
for (int i=t;i>=0;i--) //跳
if (f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
return f[x][0];//因为不相同才跳,所以再跳一次就是答案了
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
int x,y;
t=log(n)/log(2);
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
bfs(s);
while (m--)
{
scanf("%d%d",&x,&y);
printf("%d\n",LCA(x,y));
}
}