LCA最近公共祖先
概念
最近公共祖先指两个节点在一棵树上深度最大的公共的祖先节点,即这两个点在这棵树上距离最近的公共祖先节点。
Tarjan 算法介绍
使用倍增思想和动态规划。
基本思路:
- 任选一个点为根节点,从根节点开始。
- 遍历该点 u 所有子节点 v ,并标记这些子节点 v 已被访问过。
- 若是 v 还有子节点,返回 2 ,否则下一步。
- 合并 v 到 u 上。
- 寻找与当前点 u 有询问关系的点 v 。
- 若是 v 已经被访问过了,则可以确认 u 和 v 的最近公共祖先为 v 被合并到的父亲节点 a 。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+10;
int idx, e[2*N], nxt[2*N], h[N];
int n, m, s, f[N][30], deep[N];
void add(int u, int v){
nxt[++idx] = h[u];
h[u] = idx;
e[idx] = v;
}
void dfs(int u, int fa){
f[u][0] = fa;
for(int i = 1; i <= 23; i++) f[u][i] = f[f[u][i-1]][i-1];
for(int i = h[u]; i; i = nxt[i]){
int v = e[i];
if(v == fa) continue;
deep[v] = deep[u] + 1;
dfs(v, u);
}
}
int lca(int x, int y){
if(deep[x] < deep[y]) swap(x, y);
for(int i = 23; i >= 0; i--){
if(deep[f[x][i]] >= deep[y]) x = f[x][i];
}
if(x == y) return x;
for(int i = 23; i >= 0; i--){
if(f[x][i] != f[y][i]){
x = f[x][i];
y = f[y][i];
}
}
return f[x][0];
}
int main(){
deep[1] = 1;
scanf("%d%d%d", &n, &m, &s);
for(int i = 1; i < n; i++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
dfs(s, s);
while(m--){
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", lca(x, y));
}
return 0;
}

浙公网安备 33010602011771号