点的距离-LCA

给定一棵 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到公共祖先的距离再相加
	 }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值