dfs 序求 lca
下面设 \(\text{dfn}_u < \text{dfn}_v\)。
如果 \(u\) 不是 \(v\) 的祖先,那么其实询问的就是 \([\text{dfn}_u, \text{dfn}_v]\) 区间里 \(\text{dfn}\) 最小的点 \(x\) 的父亲,也就是 \(x\) 的父亲的 \(\text{dfn}\) 最小的点。证明显然。
如果 \(u\) 是 \(v\) 的祖先,那么不能管 \(\text{dfn}_u\),于是令查询区间变为 \([\text{dfn}_u + 1, \text{dfn}_v]\),这就需要特判 \(u = v\) 的情况了。
时间复杂度 \(\mathcal{O}(n \log n) \sim \mathcal{O}(1)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// typedef __int128 i128;
typedef pair<int, int> pii;
const int N = 5e5 + 10, mod = 998244353;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
cout << arg << ' ';
dbg(args...);
}
namespace Loop1st {
int n, m, rt, idx, dfn[N], f[19][N];
basic_string<int>e[N];
int get(int u, int v) { return dfn[u] < dfn[v] ? u : v; }
void dfs(int u, int fa) {
dfn[u] = ++idx; f[0][idx] = fa;
for (int v : e[u]) if (v != fa) dfs(v, u);
}
int lca(int u, int v) {
if (u == v) return u;
u = dfn[u]; v = dfn[v];
if (u > v) swap(u, v);
int d = __lg(v - u++); // d = __lg(v - (u + 1) + 1)
return get(f[d][u], f[d][v - (1 << d) + 1]);
}
void main() {
cin >> n >> m >> rt;
for (int i = 1, u, v; i < n; i++) {
cin >> u >> v;
e[u] += v;
e[v] += u;
}
dfs(rt, 0);
for (int d = 1; d < 19; d++)
for (int i = 1; i <= n - (1 << d) + 1; i++)
f[d][i] = get(f[d - 1][i], f[d - 1][i + (1 << d - 1)]);
while (m--) {
int u, v; cin >> u >> v;
cout << lca(u, v) << '\n';
}
}
}
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T = 1;
// cin >> T;
while (T--) Loop1st::main();
return 0;
}

浙公网安备 33010602011771号