Editorial for Pondo LCA II


Approach

Root the tree at vertex 11 and record an Euler tour of visits, storing the depth of the vertex at each tour index and the first index at which each vertex appears.

For a query (u,v)(u, v), the lowest common ancestor is the vertex of minimum depth on the tour between first[u]\mathrm{first}[u] and first[v]\mathrm{first}[v]. With n,q105n, q \le 10^5, a linear scan per query is too slow. Build a sparse table on the tour depths in O(nlogn)O(n \log n), then each range minimum is O(1)O(1). Overall time is O((n+q)logn)O((n + q) \log n) to build and O(n+q)O(n + q) to answer.

Solution (Python)

Code 1
import sys

sys.setrecursionlimit(1_000_000)


class SparseTable:
    def __init__(self, arr):
        self.arr = arr
        self.n = len(arr)
        self.log = [0] * (self.n + 1)
        self._compute_logs()
        self.st = self._build_sparse_table()

    def _compute_logs(self):
        for i in range(2, self.n + 1):
            self.log[i] = self.log[i // 2] + 1

    def _build_sparse_table(self):
        k = self.log[self.n] + 1
        st = [[(0, 0)] * k for _ in range(self.n)]
        for i in range(self.n):
            st[i][0] = (self.arr[i], i)
        j = 1
        while (1 << j) <= self.n:
            i = 0
            while i + (1 << j) - 1 < self.n:
                if st[i][j - 1][0] < st[i + (1 << (j - 1))][j - 1][0]:
                    st[i][j] = st[i][j - 1]
                else:
                    st[i][j] = st[i + (1 << (j - 1))][j - 1]
                i += 1
            j += 1
        return st

    def query(self, L, R):
        j = self.log[R - L + 1]
        left = self.st[L][j]
        right = self.st[R - (1 << j) + 1][j]
        if left[0] < right[0]:
            return left
        return right


data = list(map(int, sys.stdin.buffer.read().split()))
it = iter(data)
n = next(it)
q = next(it)
adj = [[] for _ in range(n)]
for _ in range(n - 1):
    u = next(it) - 1
    v = next(it) - 1
    adj[u].append(v)
    adj[v].append(u)

tour = []
tour_h = []
first = [-1] * n


def dfs(u, p, h):
    first[u] = len(tour)
    tour.append(u)
    tour_h.append(h)
    for v in adj[u]:
        if v == p:
            continue
        dfs(v, u, h + 1)
        tour.append(u)
        tour_h.append(h)


dfs(0, -1, 0)
st = SparseTable(tour_h)

out = []
for _ in range(q):
    u = next(it) - 1
    v = next(it) - 1
    l = first[u]
    r = first[v]
    if l > r:
        l, r = r, l
    _, idx = st.query(l, r)
    out.append(str(tour[idx] + 1))

print("\n".join(out))

Comments0


No comments yet

Be the first to comment.

New comment


Log in to join the discussion.