Codeforces Round #425 (Div. 2) D. Misha, Grisha and Underground(LCA)

题目链接
在这里插入图片描述
在这里插入图片描述
题意:给你一棵树, n个点,有q个询问, 每一次询问给出三个点a, b, c 问从其中两点到第三点的最长公共路径是多长。
思路:对于a,b,c求任意两点的相同路径这里有个公式:dis(a,b)+dis(c,b)-dic(a,c)/2(其中b是终点),我们只要找最大的就可以了。
对于三个点来说, LCA的一些性质: 三个点任意两点求出的三个lca 必定会有两个相同的点。那么第三个lca就是他们的公共点。 最长公共路径就是从公共点到三个点的最长的路径。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; 
const int maxn=2e5+1;
int n,deep[maxn],parent[maxn][22];
vector<int>g[maxn];
void dfs(int u,int fa)
{
	deep[u]=deep[fa]+1;
	parent[u][0]=fa;
	for(int to:g[u])
	{
		if(to==fa) continue;
		dfs(to,u);
	}
}
void init()
{
	for(int k=1;k<=21;++k)
	for(int i=1;i<=n;++i)
	parent[i][k]=parent[parent[i][k-1]][k-1];
}
int lca(int u,int v)
{
	if(deep[u]<deep[v]) swap(u,v);
	if(u!=v)
	for(int i=21;i>=0;--i) if(deep[parent[u][i]]>=deep[v]) u=parent[u][i];
	if(u==v) return u;
	for(int i=21;i>=0;--i)
	if(parent[u][i]!=parent[v][i]) u=parent[u][i],v=parent[v][i];
	return parent[u][0];
}
int getdis(int x,int y)
{
	return deep[x]+deep[y]-2*deep[lca(x,y)]+1;
}
int main()
{
	int q,t,s,f;
	scanf("%d%d",&n,&q);
	for(int i=2;i<=n;++i)
	{
		scanf("%d",&t);
		g[t].push_back(i);
		g[i].push_back(t);
	}
	deep[1]=1;
	dfs(1,0);
	init();
	while(q--)
	{
		scanf("%d%d%d",&s,&t,&f);
		int lca1=lca(s,t),lca2=lca(s,f),lca3=lca(t,f);
		int x=lca1^lca2^lca3;
		printf("%d\n",max(getdis(s,x),max(getdis(t,x),getdis(f,x))));
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值