题目大意
给个树,每次询问给出3个点a,b,c,询问a到b的路径与b到c的路径之间重合的点的个数
正解
lca不多说啥了,统计答案就是分类讨论咯(这里本人似乎讨论的重复些,读者也可以有自己的方法,所以本人自己的方法也便不解释了),另外这题卡栈(就是说dfs(递归)是系统存储的,这道题递归的太深导致系统的存储空间爆掉了),所以要打人工栈(也就是bfs)
#include<cstdio>
#include<iostream>
#include<cmath>
#define N 200007
using namespace std;
int n,q,num,cnt,f[N][20],dep[N],head[N],ans,d[N];
struct tree{
int to,nxt;
}e[N<<1];
void add(int u,int v){//链式前向星
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs(){//用人工栈
int t=1,h=0;
d[t]=1;
while(h<t){
int x=d[++h];
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(v==f[x][0]) continue;
d[++t]=v;
f[v][0]=x;
dep[v]=dep[x]+1;
}
}
}
void RMQ(){//RMQ求解lca
for(int j=1;j<=18;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
int LCA(int x,int y){
if(x==y) return x;
if(dep[x]<dep[y]) swap(x,y);
if(dep[x]>dep[y]){
for(int i=18;i>=0;i--)
if(dep[f[x][i]]>dep[y]) x=f[x][i];
x=f[x][0];
}
if(x==y) return x;
for(int i=18;i>=0;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int main(){
scanf("%d%d%d",&n,&q,&num);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs();
RMQ();
for(int i=1;i<=q;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int ab=LCA(a,b),ac=LCA(a,c),bc=LCA(b,c);
ans=0;
if(ab!=a&&ab!=b){
if(bc==ab){
ans=dep[ac]+dep[b]-dWep[ab]*2+1;
}else if(bc==b) ans=1;
else if(bc==c) ans=dep[b]-max(dep[ab],dep[bc])+1;
else ans=dep[b]-max(dep[bc],dep[ab])+1;
}else if(ab==a)
ans=dep[b]-max(dep[bc],dep[ab])+1;
else{
if(bc!=b) ans=1;
else ans=dep[ac]-dep[b]+1;
}
printf("%d\n",ans);
}
}