题目描述
给定一棵 n个结点的树,q个 询问,每次询问点 x 到点 y 两点之间的距离。
输入格式
第一行一个正整数n ,表示这棵树有 n个结点;
接下来n-1 行,每行两个整数x,y 表示x和y之间有一条连边;
然后一个整数q ,表示有 q 个询问;
接下来 q行每行两个整数x,y 表示询问 x 到 y 的距离。
输出格式
输出 q 行,每行表示每个询问的答案。
样例
输入
6
1 2
1 3
2 4
2 5
3 6
2
2 6
5 6
输出
3
4
代码
#include "bits/stdc++.h"
using namespace std;
const int N=100009;
int nxt[2*N],first[2*N],shu[2*N],tot;
int depth[N],fa[N][33];//depth[N]深度,fa[a][n]是a的pow(2,n)辈祖先
//例如fa[a][0]是a的pow(2,0)=1辈祖先,也就是a的父亲结点
void link(int x,int y)
{
nxt[++tot]=first[x];first[x]=tot;shu[tot]=y;//nxt[++tot]=first[x]记录上一个first[x]的序号
nxt[++tot]=first[y];first[y]=tot;shu[tot]=x;//nxt[++tot]=first[y]记录上一个first[y]的序号
}
void creattree(int a,int father)
{
depth[a]=depth[father]+1;
for(int i=0;i<=19;i++)
fa[a][i+1]=fa[fa[a][i]][i];
for(int e=first[a];e>0;e=nxt[e])
{
int v=shu[e];
if(v==father) continue;//如果v是自己的父节点,那么continue,不可能让自己的父节点当自己的孩子
fa[v][0]=a;//v的父亲是a
creattree(v,a);
}
}
int LAC(int x,int y)
{
if(depth[x]<depth[y])
swap(x,y);//交换x和y的值
for(int i=20;i>=0;i--)//和二进制优化一个道理
{
if(depth[fa[x][i]]>=depth[y])
x=fa[x][i];
if(x==y)//x隶属于y
return x;
}
//x不隶属于y,但此时x和y处于同一深度
for(int i=20;i>=0;i--)//和二进制优化一个道理
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
//for循环出来fa[x][i]=fa[y][i],此时i=0;
return fa[x][0];
}
int h(int x,int y)
{
int k=LAC(x,y);
return depth[x]+depth[y]-2*depth[k];
}
int main()
{
int n,q;
cin>>n;
n--;
int x,y;
while(n--)
{
cin>>x>>y;
link(x,y);
}
creattree(1,0);
cin>>q;
while(q--)
{
cin>>x>>y;
cout<<h(x,y)<<endl;
}
}