树上倍增
1. 链式前向星建树
2. bfs 预处理倍增数据,fa[i][k],i向上走步所到达的位置(设置哨兵,防止越界)
3. lca两步:(1)跳到同一层 (2)一起向上跳,跳到共同祖先节点的前一层,返回结果。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 40010, M=N*2;
int n,m;
int h[N],e[M],ne[M],idx=0;
int depth[N], fa[N][16]; // LCA paramter
int q[N];
void add(int a,int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void bfs(int root){
memset(depth, 0x3f, sizeof depth);
depth[0]=0, depth[root]=1; // depth[0] LCA哨兵
int hh = 0, tt =0;
q[0] = root;
while(hh<=tt){
int t = q[hh++];
for(int i=h[t];~i;i=ne[i]){
int j = e[i];
if(depth[j]>depth[t]+1){
depth[j] = depth[t]+1;
q[++tt] = j;
fa[j][0]=t;
for(int k=1;k<=15;k++){
fa[j][k] = fa[fa[j][k-1]][k-1];
}
}
}
}
}
int lca(int a,int b){
if(depth[a]<depth[b]) swap(a,b); //a的深度要大于b
for(int k=15;k>=0;k--)
if(depth[fa[a][k]]>=depth[b]){
a=fa[a][k];
}
if(a==b){
return a;
}
for(int k=15;k>=0;k--){
if(fa[a][k]!=fa[b][k]){ // 这里要差一步
a=fa[a][k];
b=fa[b][k];
}
}
return fa[a][0]; // 这里补上一步
}
int main(){
scanf("%d", &n);
int root = 0 ;
memset(h,-1,sizeof h);
for(int i=0;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
if(b==-1)root = a;
else add(a,b), add(b,a);
}
bfs(root);
scanf("%d",&m);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
int p = lca(a,b);
if(p==a) puts("1");
else if(p==b) puts("2");
else puts("0");
}
return 0;
}