#10130. 「一本通 4.4 例 1」点的距离(倍增求LCA)

题目描述

给定一棵 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;
	}
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值