题目链接: http://codeforces.com/contest/832/problem/D
题意:
给你一个树,和三个点a b c,其中一个点会是重点,其他两个点会是起点,问从终点到起点的最短路上相交的结点有多少。
做法:
很明显是求树上距离,用LCA的倍增能很快实现,路径相交的距离即 (dis(a,b)+dis(a,c)-dis(b,c))/2,其中a是终点,然后就上板子啦。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int dist[maxn],fa[maxn][25],n,m,q,head[maxn],now;
int flag[maxn],dep[maxn];
struct node{
int to,from,next;
}e[maxn<<1];
void dfs(int now,int f,int deps){
dep[now]=deps;
fa[now][0]=f;
for(int i=head[now];~i;i=e[i].next){
int u=e[i].to;
if(u==f) continue;
if(!dep[u]){
dist[u]=dist[now]+1;
dfs(u,now,deps+1);
}
}
}
void add(int u,int v){
e[now].to=v,e[now].from=u;
e[now].next=head[u],head[u]=now++;
}
void deal(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=24;i>=0;i--)
if(dep[x]-(1<<i)>=dep[y])
x=fa[x][i];
if(x==y) return x;
for(int i=24;i>=0;i--)
if(fa[x][i]!=fa[y][i]&&fa[x][i]!=-1)
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int getdist(int x,int y){
//cout<<LCA(x,y)<<endl;
return dist[x]+dist[y]-2*dist[LCA(x,y)];
}
void init(){
memset(head,-1,sizeof(head));
memset(dep,0,sizeof(dep));
memset(fa,-1,sizeof(fa));
}
int main(){
int x,y,z;
init();
scanf("%d%d",&n,&q);
for(int i=2;i<=n;i++){
scanf("%d",&x);
add(x,i);
}
dist[1]=0;
dfs(1,-1,0);
deal();
while(q--){
scanf("%d%d%d",&x,&y,&z);
int a=getdist(x,y);
int b=getdist(y,z);
int c=getdist(z,x);
if(a>b) swap(a,b);
if(a>c) swap(a,c);
printf("%d\n",(b+c-a)/2+1);
}
return 0;
}