Neterukun's Library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub Neterukun1993/Library

:heavy_check_mark: HL分解 (Heavy-Light Decomposition)
(Graph/Tree/HLDecomposition.py)

概要

木に対して HL 分解 (Heavy-Light Decomposition) を行い、列としてのクエリ処理を可能にするアルゴリズム。

使い方

HLDecomposition(tree: Sequence[Iterable[int]])
隣接リストで表現される木 Tree に対して HL 分解を行う。森にも対応している。根頂点を指定できないことに注意。木の場合、根は頂点 0 となる。 計算量 $O(V)$

参考

Verified with

Code

class HLDecomposition:
    def __init__(self, tree):
        self.tree = tree
        self.n = len(tree)
        self.par = [-1] * self.n
        self.size = [1] * self.n
        self.depth = [0] * self.n
        self.preorder = [0] * self.n
        self.head = [i for i in range(self.n)]
        self.k = 0

        for v in range(self.n):
            if self.par[v] == -1:
                self._dfs_pre(v)
                self._dfs_hld(v)

    def __getitem__(self, v):
        return self.preorder[v]

    def _dfs_pre(self, v):
        tree = self.tree
        stack = [v]
        order = [v]
        while stack:
            v = stack.pop()
            for chi_v in tree[v]:
                if chi_v == self.par[v]:
                    continue
                self.par[chi_v] = v
                self.depth[chi_v] = self.depth[v] + 1
                stack.append(chi_v)
                order.append(chi_v)

        for v in reversed(order):
            tree_v = tree[v]
            if len(tree_v) and tree_v[0] == self.par[v]:
                tree_v[0], tree_v[-1] = tree_v[-1], tree_v[0]
            for idx, chi_v in enumerate(tree_v):
                if chi_v == self.par[v]:
                    continue
                self.size[v] += self.size[chi_v]
                if self.size[chi_v] > self.size[tree_v[0]]:
                    tree_v[idx], tree_v[0] = tree_v[0], tree_v[idx]

    def _dfs_hld(self, v):
        stack = [v]
        while stack:
            v = stack.pop()
            self.preorder[v] = self.k
            self.k += 1
            if len(self.tree[v]) == 0:
                continue
            top = self.tree[v][0]
            for chi_v in reversed(self.tree[v]):
                if chi_v == self.par[v]:
                    continue
                if chi_v == top:
                    self.head[chi_v] = self.head[v]
                else:
                    self.head[chi_v] = chi_v
                stack.append(chi_v)

    def lca(self, u, v):
        while u != -1 and v != -1:
            if self.preorder[u] > self.preorder[v]:
                u, v = v, u
            if self.head[u] == self.head[v]:
                return u
            v = self.par[self.head[v]]
        return -1

    def distance(self, u, v):
        lca_uv = self.lca(u, v)
        if lca_uv == -1:
            return -1
        else:
            return self.depth[u] + self.depth[v] - 2 * self.depth[lca_uv]

    def range_vertex_path(self, u, v):
        while True:
            if self.preorder[u] > self.preorder[v]:
                u, v = v, u
            l = max(self.preorder[self.head[v]], self.preorder[u])
            r = self.preorder[v]
            yield l, r + 1
            if self.head[u] != self.head[v]:
                v = self.par[self.head[v]]
            else:
                return

    def range_edge_path(self, u, v):
        while True:
            if self.preorder[u] > self.preorder[v]:
                u, v = v, u
            if self.head[u] != self.head[v]:
                yield self.preorder[self.head[v]], self.preorder[v] + 1
                v = self.par[self.head[v]]
            else:
                if u != v:
                    yield self.preorder[u] + 1, self.preorder[v] + 1
                break

    def range_subtree(self, u):
        return self.preorder[u], self.preorder[u] + self.size[u]
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.12.4/x64/lib/python3.12/site-packages/onlinejudge_verify/documentation/build.py", line 71, in _render_source_code_stat
    bundled_code = language.bundle(stat.path, basedir=basedir, options={'include_paths': [basedir]}).decode()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.4/x64/lib/python3.12/site-packages/onlinejudge_verify/languages/python.py", line 96, in bundle
    raise NotImplementedError
NotImplementedError
Back to top page