题面:给定一颗n个节点的树,根节点编号为1,有Q组询问,每次给定一对节点编号(x,y),求(x,y)的最近公共祖先。
范围:1 <= n <= 1E3; 1 <= Q <= 1E3
分析:求LCA有多种方法,这里用的是倍增法,预处理时间O(nlogn),单次查询时间O(logn),支持在线。
#include <bits/stdc++.h>
const int N = 1005;
int dep[N], fa[N][11];
std::vector<int> adj[N];
void dfs(int x, int p) {
fa[x][0] = p;
dep[x] = dep[p] + 1;
for (int i = 1; i <= 10; i++) {
fa[x][i] = fa[fa[x][i-1]][i-1];
}
for (auto i : adj[x]) if (i != p) {
dfs(i, x);
}
}
int lca(int x, int y) {
if (dep[x] < dep[y]) std::swap(x, y);
for (int i = 10; i >= 0; i--) {
if (dep[fa[x][i]] >= dep[y]) {
x = fa[x][i];
}
}
if (x == y) return x;
for (int i = 10; i >= 0; i--) {
if (fa[x][i] != fa[y][i]) {
x = fa[x][i];
y = fa[y][i];
}
}
return fa[x][0];
}
void solve() {
int n;
std::cin >> n;
for (int i = 1; i < n; i++) {
int u, v;
std::cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs(1, 1);
int Q;
std::cin >> Q;
while (Q--) {
int a, b;
std::cin >> a >> b;
std::cout << lca(a,b) << "\n";
}
}
int main() {
std::cin.tie(0)->sync_with_stdio(0);
int t = 1;
while (t--) solve();
return 0;
}
标签:倍增