题目大意:给你一棵树,有 q 个询问,每次给你三个数,其中一个当做终点,两个当做起点,问你这样两条路有多少公共节点。
思路:LCA,如果只问你 a,b 分别到 c 的两条路有多少个公共节点的话,就是( dis( a , c) + dis( b , c) - dis( a , b ) ) / 2 + 1 ;
所以我们知道求出每两个点之间的最短距离,(最长的 + 第二长 - 最短的)/ 2 + 1;

#include<bits/stdc++.h> #define pb push_back using namespace std; const int N=1e5+5; int vs[2*N],dp[2*N][25],d[N],tot=0,f[N],w[3]; vector<int> e[N]; int n,q; void dfs(int u,int p,int s) { vs[++tot]=u; d[u]=s; f[u]=tot; for(int i=0;i<e[u].size();i++) { int to=e[u][i]; if(to==p) continue; dfs(to,u,s+1); vs[++tot]=u; } } void work_rmq() { for(int i=1;i<=tot;i++) dp[i][0]=vs[i]; int up=log(tot)/log(2); for(int j=1;j<=up;j++) { int t=(1<<j)-1; for(int i=1;i+t<=tot;i++) { int a=dp[i][j-1],b=dp[i+(1<<(j-1))][j-1]; if(d[a]<=d[b]) dp[i][j]=a; else dp[i][j]=b; } } } int get_lca(int u,int v) { int l,r; if(f[u]<f[v]) l=f[u],r=f[v]; else l=f[v],r=f[u]; int j=log(r-l+1)/log(2); int a=dp[l][j],b=dp[r-(1<<j)+1][j]; if(d[a]<d[b]) return a; else return b; } int get_dis(int u,int v) { int f=get_lca(u,v); int res=fabs(d[u]-d[f])+fabs(d[v]-d[f]); return res; } int main() { cin>>n>>q; for(int i=2;i<=n;i++) { int g; scanf("%d",&g); e[i].pb(g); e[g].pb(i); } dfs(1,-1,0); work_rmq(); while(q--) { int ans[3]; for(int i=0;i<=2;i++) scanf("%d",&w[i]); ans[0]=get_dis(w[0],w[1]); ans[1]=get_dis(w[0],w[2]); ans[2]=get_dis(w[1],w[2]); sort(ans,ans+3); printf("%d ",(ans[2]+ans[1]-ans[0])/2+1); } return 0; }