題目鏈接:Codeforces - Misha, Grisha and Underground
我們可以枚舉終點,問題就轉變爲a->c和b->c的交點個數。
我們分別考慮b是c到a的子樹中,或者不是,然後可以發現公式:(dis(a,c)+dis(b,c)-dis(a,b))/2+1;
AC代碼:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,q;
int pos[N],bl[N],dep[N],f[N],son[N],sz[N],cnt;
vector<int> g[N];
void dfs1(int x){
sz[x]=1;
for(auto to:g[x]){
if(f[x]==to) continue;
f[to]=x; dep[to]=dep[x]+1; dfs1(to); sz[x]+=sz[to];
if(sz[to]>sz[son[x]]) son[x]=to;
}
}
void dfs2(int x,int belong){
pos[x]=++cnt; bl[x]=belong;
if(son[x]) dfs2(son[x],belong);
for(auto to:g[x]) if(to!=son[x]&&dep[to]>dep[x]) dfs2(to,to);
}
inline int lca(int x,int y){
while(bl[x]!=bl[y]){
if(dep[bl[x]]<dep[bl[y]]) swap(x,y); x=f[bl[x]];
}
return dep[x]>dep[y]?y:x;
}
inline int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
inline int calc(int a,int b,int c){
return (dis(a,c)+dis(b,c)-dis(a,b))/2+1;
}
signed main(){
cin>>n>>q;
for(int i=2,x;i<=n;i++) scanf("%d",&x),g[x].push_back(i);
dfs1(1),dfs2(1,1);
for(int i=1,a,b,c;i<=q;i++){
scanf("%d %d %d",&a,&b,&c);
printf("%d\n",max(calc(a,b,c),max(calc(a,c,b),calc(b,c,a))));
}
return 0;
}