Source code for titan_pylib.graph.lca
1from titan_pylib.data_structures.sparse_table.sparse_table_RmQ import SparseTableRmQ
2
3
[docs]
4class LCA:
5 """LCA を定数倍良く求めます。
6
7 :math:`< O(NlogN), O(1) >`
8 https://github.com/cheran-senthil/PyRival/blob/master/pyrival/graphs/lca.py
9 """
10
11 def __init__(self, G: list[list[int]], root: int) -> None:
12 """根が ``root`` の重み無し隣接リスト ``G`` で表されるグラフに対して LCA を求めます。
13 時間・空間 :math:`O(n\\log{n})` です。
14
15 Args:
16 G (list[list[int]]): 隣接リストです。
17 root (int): 根です。
18 """
19 _n = len(G)
20 path = [-1] * _n
21 nodein = [-1] * _n
22 par = [-1] * _n
23 curtime = -1
24 stack = [root]
25 while stack:
26 v = stack.pop()
27 path[curtime] = par[v]
28 curtime += 1
29 nodein[v] = curtime
30 for x in G[v]:
31 if nodein[x] != -1:
32 continue
33 par[x] = v
34 stack.append(x)
35 self._n = _n
36 self._path = path
37 self._nodein = nodein
38 self._st: SparseTableRmQ[int] = SparseTableRmQ((nodein[v] for v in path), e=_n)
39
[docs]
40 def lca(self, u: int, v: int) -> int:
41 """頂点 ``u`` と頂点 ``v`` の LCA を返します。
42 :math:`O(1)` です。
43 """
44 if u == v:
45 return u
46 l, r = self._nodein[u], self._nodein[v]
47 if l > r:
48 l, r = r, l
49 return self._path[self._st.prod(l, r)]
50
[docs]
51 def lca_mul(self, a: list[int]) -> int:
52 """頂点集合 ``a`` の LCA を返します。"""
53 if all(a[i] == a[i + 1] for i in range(len(a) - 1)):
54 return a[0]
55 l = self._n + 1
56 r = -l
57 for e in a:
58 e = self._nodein[e]
59 if l > e:
60 l = e
61 if r < e:
62 r = e
63 return self._path[self._st.prod(l, r)]