树上倍增
1. 链式前向星建树
2. bfs 预处理倍增数据,fa[i][k],向上走$2^{k-1}$步所到达的位置(设置哨兵,放置越界)
3. lca两步:(1)跳到同一层 ()一起向上跳,跳到共同祖先节点的前一层,返回结果。
#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;
}