贴几篇学习博客:
CSDN - 青烟绕指柔!的博客 - 倍增算法
CSDN - Nekroz_的博客
CSDN - Dust_Heart的博客
#include <iostream>
#include <algorithm>
#include <cstring>
#include <math.h>
#include <stdio.h>
using namespace std;
// LCA 最近公共祖先 倍增
const int N = 5e5+10;
int n ,m ,s;
int e[2*N], pr[2*N], h[2*N], idx = 0; // 链式前向星
int depth[N], f[N][30]; // depth[]深度 f[i][j]是i的2^j级祖先
// 加边 (两个无向边)
void add(int x, int y){
e[++idx] = y, pr[idx] = h[x], h[x] = idx;
}
// dfs得到每一点的 深度 和 所有祖先 ,根结点深度为1
void dfs(int x, int fa){
depth[x] = depth[fa]+1, f[x][0] = fa;
for(int i = 1; (1<<i) <= depth[x]; i++) f[x][i] = f[f[x][i-1]][i-1];
for(int i = h[x]; i; i = pr[i]) {
if(e[i] != fa) dfs(e[i],x);
}
}
// 计算最近公共祖先 倍增
int lca(int x, int y){
//1. 将x y跳到同一层(同一高度)
//2. 将x y按照距离从高到低跳,若祖先相同,说明此时有跳过的可能,继续看下一次;
// 若不同则跳到该层,从该层继续跳(不会跳不到,可以手动模拟一下)
if(depth[x] < depth[y]) swap(x,y);
while(depth[x] > depth[y]) x = f[x][(int)(log2(depth[x] - depth[y]))];
if(x == y) return x;
for(int i = log2(depth[x]); i >= 0; i--)
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int main(){
// n-1条无向边 m次询问 s为根节点
scanf("%d%d%d",&n,&m,&s);
for(int i = 1; i < n; i++){
int x, y;
scanf("%d%d",&x,&y);
add(x,y), add(y,x);
}
dfs(s,0);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
cout<<lca(a,b)<<endl;
}
}