题目链接
题意:给你一棵树, 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))));
}
}