- 2022tysc0306 的博客
倍增求lca
- 2024-12-17 14:10:47 @
倍增求 的方法主要有两个步骤:
把 和 提到相同深度。
和 同步跳,跳到 。
步骤
先求出 和 ,这时只需要在 中就可以完成:
定义 表示 节点的第 个祖先,有一个非常巧妙的递推关系:
意思是从 节点先跳到 的第 个祖先,再从 个祖先跳到 个祖先。
简单来说,就是 。
在此要特判一下 ,有可能 ,这种情况下 为 的祖先。
步骤
每一次跳 ,直到跳到 为止。
有两种情况:
-
,这是一个公共祖先,但不是 ,说明跳过头了,回去换一个更小的跳。
-
,说明还没跳到公共祖先,那么更新 。
最后 就是 。
#include <iostream>
#include <vector>
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dow(i, j, k) for(int i = j; i >= k; i--)
using namespace std;//命名空间
const int N = 5e5 + 5;
int n, m, s, fa[N][25], d[N];
vector<int> g[N];
inline void dfs(int u, int fat)
{
d[u] = d[fat] + 1;//计算深度
fa[u][0] = fat;//初始化,u的父节点为fat
for(int i = 1; (1 << i) <= d[u]; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];//初始化,最多跳到根节点
for(int i = 0; i < (int)g[u].size(); i++){
int v = g[u][i];
if(v == fat) continue;
dfs(v, u);//向下搜索
}
}
inline int lca(int x, int y)//lca的部分
{
if(d[x] < d[y]) swap(x, y);//让x的深度更大
dow(i, 20, 0)
if(d[x] - (1 << i) >= d[y]) x = fa[x][i];
if(x == y) return x;//lca(x,y)=x,直接返回
dow(i, 20, 0)
if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];//向上跳
return fa[x][0];//最终的lca
}
int main()//主函数
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m >> s;
for(int i = 1; i < n; i++){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(s, 0);
while(m--){
int x, y;
cin >> x >> y;
int z = lca(x, y);
cout << z << "\n";
}
return 0;//华丽结束
}