Loading

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;
}
posted @ 2026-01-24 15:20  循环一号  阅读(3)  评论(0)    收藏  举报