Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
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.
HLD | |
|
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
isEdge
parameter 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).
TreeMonoid | |
|
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
.