Editorial for Kinship


Approach

The superiors form a tree rooted at goblin 00. For a query (a,b)(a, b), the closest shared superior is the lowest common ancestor lca(a,b)\mathrm{lca}(a, b).

Precompute binary lifting tables up[v][j]up[v][j]: the 2j2^j-th superior of vv. To answer a query, lift the deeper node up to the same depth as the shallower one. If they meet, that node is the answer. Otherwise, lift both nodes together as high as possible while their ancestors differ, then take one final step to the parent. Each query runs in O(log⁡n)O(\log n) after O(nlog⁡n)O(n \log n) preprocessing. Overall time is O((n+q)log⁡n)O((n + q) \log n).

Solution (C++)

Code 1
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, q;
    cin >> n >> q;

    vector<vector<int> > adj(n);
    for (int i = 0; i < n - 1; i++) {
        int a, b;
        cin >> a >> b;
        adj[a].push_back(b);
        adj[b].push_back(a);
    }

    vector<int> parent(n, -1);
    vector<int> depth(n, 0);
    stack<int> st;
    st.push(0);
    parent[0] = 0;
    while (!st.empty()) {
        int v = st.top();
        st.pop();
        for (size_t i = 0; i < adj[v].size(); i++) {
            int to = adj[v][i];
            if (parent[to] != -1) {
                continue;
            }
            parent[to] = v;
            depth[to] = depth[v] + 1;
            st.push(to);
        }
    }

    int LOGN = 1;
    while ((1 << LOGN) <= n) {
        LOGN++;
    }
    vector<vector<int> > up(n, vector<int>(LOGN));
    for (int i = 0; i < n; i++) {
        up[i][0] = parent[i];
    }
    for (int j = 1; j < LOGN; j++) {
        for (int i = 0; i < n; i++) {
            up[i][j] = up[up[i][j - 1]][j - 1];
        }
    }

    auto lift = [&](int v, int dist) {
        for (int j = 0; j < LOGN; j++) {
            if ((dist >> j) & 1) {
                v = up[v][j];
            }
        }
        return v;
    };

    auto lca = [&](int a, int b) {
        if (depth[a] < depth[b]) {
            swap(a, b);
        }
        a = lift(a, depth[a] - depth[b]);
        if (a == b) {
            return a;
        }
        for (int j = LOGN - 1; j >= 0; j--) {
            if (up[a][j] != up[b][j]) {
                a = up[a][j];
                b = up[b][j];
            }
        }
        return up[a][0];
    };

    for (int qi = 0; qi < q; qi++) {
        int a, b;
        cin >> a >> b;
        cout << lca(a, b) << "\n";
    }
}

Comments0


No comments yet

Be the first to comment.

New comment


Log in to join the discussion.