| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
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
- type VertexHLD = Vertex
- data HLD = HLD {}
- hldOf :: forall w. SparseGraph w -> HLD
- hldOf' :: forall w. SparseGraph w -> Vertex -> HLD
- lcaHLD :: HLD -> Vertex -> Vertex -> Vertex
- lengthHLD :: HLD -> Vertex -> Vertex -> Int
- _segmentsHLD :: Bool -> HLD -> Vertex -> Vertex -> [(VertexHLD, VertexHLD)]
- edgeSegmentsHLD :: HLD -> Vertex -> Vertex -> [(VertexHLD, VertexHLD)]
- vertSegmentsHLD :: HLD -> Vertex -> Vertex -> [(VertexHLD, VertexHLD)]
- foldHLD :: (Monoid mono, Monad m) => Bool -> HLD -> (VertexHLD -> VertexHLD -> m mono) -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono
- foldEdgesCommuteHLD :: (Monoid mono, Monad m) => HLD -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono
- foldEdgesHLD :: (Monoid mono, Monad m) => HLD -> (VertexHLD -> VertexHLD -> m mono) -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono
- foldVertsCommuteHLD :: (Monoid mono, Monad m) => HLD -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono
- foldVertsHLD :: (Monoid mono, Monad m) => HLD -> (VertexHLD -> VertexHLD -> m mono) -> (VertexHLD -> VertexHLD -> m mono) -> Vertex -> Vertex -> m mono
- subtreeSegmentsHLD :: HLD -> Vertex -> (VertexHLD, VertexHLD)
- isInSubtreeHLD :: HLD -> Vertex -> Vertex -> Bool
- ancestorHLD :: HLD -> Vertex -> Vertex -> Vertex
- jumpHLD :: HLD -> Vertex -> Vertex -> Int -> Maybe Vertex
- pathHLD :: HLD -> Vertex -> Vertex -> [Vertex]
- data TreeMonoid a s = TreeMonoid {
- hldTM :: !HLD
- isCommuteTM :: !Bool
- isEdgeTM :: !Bool
- streeFTM :: !(SegmentTree s a)
- streeBTM :: !(SegmentTree s (Dual a))
- _buildRawTM :: (PrimMonad m, Monoid a, Unbox a) => HLD -> Bool -> Bool -> Vector a -> m (TreeMonoid a (PrimState m))
- buildVertTM :: (PrimMonad m, Monoid a, Unbox a) => HLD -> Bool -> Vector a -> m (TreeMonoid a (PrimState m))
- edgeVertsHLD :: Unbox a => HLD -> Vector (Vertex, Vertex, a) -> Vector (Vertex, a)
- buildEdgeTM :: (PrimMonad m, Monoid a, Unbox a) => HLD -> Bool -> Vector (Vertex, a) -> m (TreeMonoid a (PrimState m))
- foldTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> Vertex -> m a
- foldSubtreeVertsTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a
- foldSubtreeEdgeTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a
- readTM :: (PrimMonad m, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a
- writeTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> a -> m ()
- exchangeTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> a -> m a
- modifyTM :: (PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> (a -> a) -> Int -> m ()
Documentation
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
| |
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
_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 bel > r. - LCA is omitted when
isEdgeparameter is set toTrue(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.
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.
Utilities
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.