倍增最近公共祖先(LCA)
倍增最近公共祖先(LCA)
标签(空格分隔): 模板
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5e5 + 50;
int n, m, s;
int fa[MAXN][50], lg[MAXN], dep[MAXN];
vector<int> e[MAXN];
inline int read()
{
int res = 0;
char ch = getchar();
while(48 > ch || ch > 57){
ch = getchar();
}
while(48 <= ch && ch <= 57){
res = (res << 3) + (res << 1) + (ch - 48);
ch = getchar();
}
return res;
}
void add_edge(int u, int v)
{
e[u].push_back(v);
e[v].push_back(u);
return;
}
void build_lca(int now)
{
// cout << "*";
for(int i = 1; i <= 30 && fa[now][i - 1]; i ++ )
fa[now][i] = fa[fa[now][i - 1]][i - 1];
for(int v : e[now]){
if(v == fa[now][0]) continue;
dep[v] = dep[now] + 1;
fa[v][0] = now;
build_lca(v);
}
return;
}
int get_lca(int u, int v)
{
if(dep[u] < dep[v]) swap(u, v);
while(dep[u] > dep[v])
u = fa[u][lg[dep[u] - dep[v]] - 1];
if(u == v) return u;
for(int i = lg[dep[u]]; i >= 0; i --){
if(fa[u][i] != fa[v][i])
u = fa[u][i], v = fa[v][i];
}
return fa[u][0];
}
int main()
{
n = read(), m = read(), s = read();
for(int i = 0; i < n - 1; i ++){
int u = read(), v = read();
add_edge(u, v);
}
build_lca(s);
for(int i = 1; i <= n; i ++)
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
for(int i = 0; i < m; i ++){
int u = read(), v = read();
printf("%d\n", get_lca(u, v));
}
return 0;
}
胜负师是求道者与苦行僧的结合。