​题目传送门​

一、理解与感悟

  • 倍增思想,正向拆,反向查
  • 性能从\(O(n)\)优化到\(O(log_2(n))\)
  • 最终停留在\(lca\)的下一层
  • 如果\(n\)个点形成一条链,是最深的深度,此时 \(2^k\)需要大于\(N\),此题\(N=500010\),\(2^{16}=65536\)不够,需要开到\(2^{20}\)

二、实现代码

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 500010, M = 500010 * 2;
//邻接表
int e[M], h[N], idx, ne[M];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int dep[N];
int f[N][22];
void bfs(int t) {
dep[t] = 1;
queue<int> q;
q.push(t);
while (q.size()) {
int u = q.front();
q.pop();
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!dep[j]) {
dep[j] = dep[u] + 1;
q.push(j);
f[j][0] = u;
for (int k = 1; k <= 20; k++)
f[j][k] = f[f[j][k - 1]][k - 1];
}
}
}
}
int lca(int a, int b) {
if (dep[a] < dep[b]) swap(a, b);
for (int k = 20; k >= 0; k--)
if (dep[f[a][k]] >= dep[b]) a = f[a][k];
if (a == b) return a;
for (int k = 20; k >= 0; k--)
if (f[a][k] != f[b][k])
a = f[a][k], b = f[b][k];
return f[a][0];
}
int main() {
memset(h, -1, sizeof h);
int n, m, s;
cin >> n >> m >> s;
int a, b;
for (int i = 0; i < n - 1; i++) {
cin >> a >> b;
add(a, b), add(b, a);
}
bfs(s);
for (int i = 1; i <= m; i++) {
cin >> a >> b;
printf("%d\n", lca(a, b));
}
return 0;
}