toy-lib-0.1.0.0
Safe HaskellSafe-Inferred
LanguageHaskell2010

Data.Graph.Tree.Hld

Description

Heavy-light decomposition or Centroid Path Decomposition construction. Heavily inspired by cojna/iota and maspypy/library.

HLD lets you find LCA in \(O(\log V)\) time and lets you fold monoids on a path in \(O(\log^2 V)\) time with the help of segment trees.

Synopsis

Documentation

type VertexHLD = Vertex #

Vertex reindexed by indexHLD.

data HLD #

HLD splits a tree into lines. Lines are often called "paths", but here we say "lines" for avoiding word conflicts.

Example

Original tree

Consider a tree with arbitrary vertex order:

 0--8--7--3--1--2--12--13--15--14     XX: vertex
    |        |                         --: edge
10--5        11--8--6                   |: edge
    |
    4

indexHLD: Vertex -> vertexHLD

The tree vertices are reindexed with indexHLD, ensuring vertices in each line have consecutive numbers:

 0==1==2==3==4==5==6==7==8==9     XX: vertex
    |        |                     ==: edge on the same line
14==13       10==11==12            |: edge between different lines
    |
    15

Note that vertices on higher lines are assigned smaller numbers.

headHLD: Vertex -> Vertex

headHLD can be used for finding LCA of two vertices. To find the LCA, move up to the head, go up to the parental line's vertex and repeat until they are on the same line.

 0==0==0==0==0==0==0==0==0==0
    |     |
 5==5      11==11==11
    |
    4

headHLD also works for identifying lines. When two vertices are on the same line, they have the same head.

parentHLD: Vertex -> Vertex

parentHLD lets you go up to the parental line's vertex from a head:

(-1)==0==8==7==3==1==2==12==13==15
      |        |
   5==8        1==11=8
      |
      5

Segment tree integration

With HLD, we can find a path between two vertices u, v: u -> lca(u, v) -> v. The path is decomposed into segments where segment trees can be integrated as in TreeMonoid.

Vertex monoid folding on a path

If vertices have weights, use foldVertsCommuteHLD or foldVertsHLD.

Edge monoid folding on a path

If edges have weights, you can either treat the edges as new vertices or assign edge weights to the depper index.

Idea 1. Treat edges as new vertices.

       convert
o--o--o  --> o-x-o-x-o

Idea 2. Assign edge weight to the deeper vertex. This is the idea of foldEdgesCommuteHLD and foldEdgesHLD:

  o
  | <--- edge 1
  o <- write wegiht 1 here
  | <--- edge 2
  o <- write wegiht 2 here

Subtree folding

Subtree VertexHLD is contiguous. We can easily find the corredponding (l, r) paris of VertexHLD that corresopnds to the subtree by remembering the subtree sizes.

Constructors

HLD 

Fields

Instances

Instances details
Show HLD # 
Instance details

Defined in Data.Graph.Tree.Hld

Methods

showsPrec :: Int -> HLD -> ShowS #

show :: HLD -> String #

showList :: [HLD] -> ShowS #

Eq HLD # 
Instance details

Defined in Data.Graph.Tree.Hld

Methods

(==) :: HLD -> HLD -> Bool #

(/=) :: HLD -> HLD -> Bool #

Construction

hldOf :: forall w. SparseGraph w -> HLD #

\(O(V)\) Constructs HLD.

hldOf' :: forall w. SparseGraph w -> Vertex -> HLD #

\(O(V)\) Constructs HLD with root vertex specified.

LCA

lcaHLD :: HLD -> Vertex -> Vertex -> Vertex #

\(O(\log V)\) HLD calculation.

Typical Problems

ABC 133 - F

lengthHLD :: HLD -> Vertex -> Vertex -> Int #

\(O(\log V)\) Path length between two vertices.

_segmentsHLD :: Bool -> HLD -> Vertex -> Vertex -> [(VertexHLD, VertexHLD)] #

\(O(\log V)\) Shared implementation of edgeSegmentsHLD and vertSegmentsHLD, which returns `[l, r]` pairs for each segment.

  • The return type is VertexHLD.
  • Note that each (l, r) pair can be l > r.
  • LCA is omitted when isEdge parameter is set to True (the trick to put edge weights to vertices).

edgeSegmentsHLD :: HLD -> Vertex -> Vertex -> [(VertexHLD, VertexHLD)] #

\(O(\log V)\) Returns inclusive edge vertex pairs.

vertSegmentsHLD :: HLD -> Vertex -> Vertex -> [(VertexHLD, VertexHLD)] #

\(O(\log V)\) Returns inclusive vertex pairs per.

foldHLD :: (Monoid mono, Monad m) => Bool -> HLD -> (VertexHLD -> VertexHLD -> m mono) -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono #

\(O(\log^2 V)\) Folds path between v1 and v2. Use specialized methods for simplisity.

foldEdgesCommuteHLD :: (Monoid mono, Monad m) => HLD -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono #

\(O(\log^2 V)\) Folds commutative monoids on a tree edges using HLD. Prefer to use the wrapper TreeMonoid.

Typical Problems

foldEdgesHLD :: (Monoid mono, Monad m) => HLD -> (VertexHLD -> VertexHLD -> m mono) -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono #

\(O(\log^2 V)\) Folds commutative monoids on a tree vertices using HLD. Prefer to use the wrapper TreeMonoid.

TODO: verify

foldVertsCommuteHLD :: (Monoid mono, Monad m) => HLD -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono #

\(O(\log^2 V)\) Folds commutative monoids on a tree vertices using HLD. Prefer to use the wrapper TreeMonoid.

Typical Problems

foldVertsHLD :: (Monoid mono, Monad m) => HLD -> (VertexHLD -> VertexHLD -> m mono) -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono #

\(O(\log^2 V)\) Folds non-commutative monoids on a tree vertices using HLD. Prefer to use the wrapper TreeMonoid.

Typical Problems

Subtree

subtreeSegmentsHLD :: HLD -> Vertex -> (VertexHLD, VertexHLD) #

\(O(1)\) Returns (start, end) VertexHLD that corresponds to the subtree segments rooted at the subtreeRoot.

isInSubtreeHLD :: HLD -> Vertex -> Vertex -> Bool #

\(O(1)\) Returns True if u is in a subtree of r.

Jump

ancestorHLD :: HLD -> Vertex -> Vertex -> Vertex #

\(O(\log V)\) Go up i times from the parent node to the implicit root node.

jumpHLD :: HLD -> Vertex -> Vertex -> Int -> Maybe Vertex #

\(O(\log V)\) Returns i-th vertex of a path between u, v.

https://judge.yosupo.jp/problem/jump_on_tree

Utilities

pathHLD :: HLD -> Vertex -> Vertex -> [Vertex] #

\(O(\log V)\) Returns path between u and v.

TreeMonoid for path folding

data TreeMonoid a s #

HLD wrapper for folding paths on a tree using HLD and segment tree(s).

Constructors

TreeMonoid 

Fields

Construction

_buildRawTM :: (PrimMonad m, Monoid a, Unbox a) => HLD -> Bool -> Bool -> Vector a -> m (TreeMonoid a (PrimState m)) #

\(O(V)\) Shared implementation of buildVertTM and buildEdgeTM.

buildVertTM :: (PrimMonad m, Monoid a, Unbox a) => HLD -> Bool -> Vector a -> m (TreeMonoid a (PrimState m)) #

\(O(V)\) Builds a TreeMonoid on vertices.

edgeVertsHLD :: Unbox a => HLD -> Vector (Vertex, Vertex, a) -> Vector (Vertex, a) #

\(O(V)\) Map weightened edges into (Vertex, a) pairs. The output is the input to buildEdgeTM.

buildEdgeTM :: (PrimMonad m, Monoid a, Unbox a) => HLD -> Bool -> Vector (Vertex, a) -> m (TreeMonoid a (PrimState m)) #

\(O(V)\) Builds a TreeMonoid on edges. **The input must be the output of edgeVertsHLD**.

Segment tree methods

foldTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> Vertex -> m a #

\(O(\log^2 V)\) Folds a path between two vertices.

foldSubtreeVertsTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a #

\(O(\log V)\) Folds commute monoids on vertives of a subtree.

foldSubtreeEdgeTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a #

\(O(\log V)\) Folds commute monoids on edges of a subtree. TODO: test

readTM :: (PrimMonad m, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a #

\(O(\log V)\) Reads a TreeMonoid value on a Vertex.

writeTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> a -> m () #

\(O(\log V)\) Write a TreeMonoid value on a Vertex.

exchangeTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> a -> m a #

\(O(\log V)\) Exchanges a TreeMonoid value on a Vertex.

modifyTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> (a -> a) -> Int -> m () #

\(O(\log V)\) Modifies a TreeMonoid value on a Vertex.