有一棵 \(n\) 个节点的树,一共 \(q\) 次询问,每次询问给定 \(3\) 个点,求两条起点终点在这三个点上且不完全重合的路径的最多公共节点数。
Solution
枚举公共点,答案为 \((dis(a,b) + dis(a,c) - dis(b,c)) / 2 + 1\)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int n,q,t1,t2,t3;
vector <int> g[N];
int dep[N],fa[N][20],vis[N];
void dfs(int p) {
vis[p]=1;
for(int q:g[p]) {
if(vis[q]) continue;
dep[q]=dep[p]+1;
fa[q][0]=p;
dfs(q);
}
}
int lca(int p,int q) {
if(dep[p]<dep[q]) swap(p,q);
for(int i=18;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) p=fa[p][i];
for(int i=18;i>=0;--i) if(fa[p][i]-fa[q][i]) p=fa[p][i], q=fa[q][i];
if(p-q) return fa[p][0];
return p;
}
int dist(int p,int q) {
int l=lca(p,q);
return dep[p]+dep[q]-2*dep[l];
}
int calc(int a,int b,int c) {
return (dist(a,b)+dist(a,c)-dist(b,c))/2;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n>>q;
for(int i=1;i<n;i++) {
cin>>t1;
g[i+1].push_back(t1);
g[t1].push_back(i+1);
}
dep[1]=1;
dfs(1);
for(int i=1;i<=18;i++) {
for(int j=1;j<=n;j++) {
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
for(int i=1;i<=q;i++) {
cin>>t1>>t2>>t3;
cout<<max(max(calc(t1,t2,t3),calc(t2,t3,t1)),calc(t3,t1,t2))+1<<endl;
}
}