给定一棵 n 个点的树,Q 个询问,每次询问点 x 到点y 两点之间的距离。
输入格式
第一行一个正整数 n,表示这棵树有 n 个节点;
接下来 n−1 行,每行两个整数 x,y 表示 x,y 之间有一条连边;
然后一个整数 Q,表示有 Q 个询问;
接下来 QQ 行每行两个整数 x,y 表示询问 x 到 y 的距离。
输出格式
输出 Q 行,每行表示每个询问的答案。
思路:LCA模板题
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=5e5+10;
int head[N],cnt=-1,de[N],fa[N][21];
struct l
{
int next,to;
} p[N];
void add(int from,int to)
{
p[++cnt].to=to;
p[cnt].next=head[from];
head[from]=cnt;
}
void dfs(int now,int father)//进行深度和祖先的初始化
{
de[now]=de[father]+1;//当前点的深度等于它父亲深度加1
for(int i=1;(1<<i)<=de[now];i++)//找到它的2的n次方的祖先
{
fa[now][i]=fa[fa[now][i-1]][i-1];//当前点的第2的i次方祖先等于它先找它的第2的i-1次方祖先再找2的i-1次方组先,比如你想要找到它的第4个祖先可以先往上找2位祖先,找到后再往上找2位
}//2的n次方找完意味着其他的也可以找到如果我们想找它的第5位祖先我们就可以先往上找2的2次方祖先再往上找2的0次方祖先
for(int i=head[now];i!=-1;i=p[i].next)
{
if(p[i].to==father) continue;
fa[p[i].to][0]=now;
dfs(p[i].to,now);
}
}
int LCA(int x,int y)
{
if(de[x]<de[y]) swap(x,y);//我们把x尽可能的深
for(int i=20;i>=0;i--)
{
if(de[fa[x][i]]>=de[y]) x=fa[x][i];//尽可能的把x往上跳让他和y在同一深度
if(x==y) return x;
}
for(int i=20;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])//让他们两个同时往上跳直到找到他们最近公共祖先的孩子
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];//当前x的父亲就是最近公共祖先
}
int main()
{
int n,m,i,j;
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(i=0;i<n-1;i++)
{
int a,b;
scanf("%d %d",&a,&b);
add(a,b);
//add(b,a);
}
scanf("%d",&m);
dfs(1,0);
for(i=0;i<m;i++)
{
int a,b;
scanf("%d %d",&a,&b);
//printf("<<%d\n",LCA(a,b));
printf("%d\n",de[a]+de[b]-2*de[LCA(a,b)]);//算距离的时候就是分别求出x和y到公共祖先的距离再相加
}
}