Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
ds2-notes
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Model registry
Analyze
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
datovky
ds2-notes
Commits
c57e1f1c
Commit
c57e1f1c
authored
3 years ago
by
Ondřej Mička
Browse files
Options
Downloads
Patches
Plain Diff
Graphs: Intro to link-cut; minor changes
parent
1185c0e3
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
om-graphs/graphs.tex
+95
-20
95 additions, 20 deletions
om-graphs/graphs.tex
om-graphs/range-tree.ipe
+9
-9
9 additions, 9 deletions
om-graphs/range-tree.ipe
with
104 additions
and
29 deletions
om-graphs/graphs.tex
+
95
−
20
View file @
c57e1f1c
...
...
@@ -6,23 +6,25 @@
\def\TODO
{{
\bf
TODO
}}
\def\NOTE
{{
\bf
NOTE
}}
\def\LCA
{
\op
{
LCA
}}
\def\Root
{
\op
{
Root
}}
\def\Expose
{
\op
{
Expose
}}
\def\Parent
{
\op
{
Parent
}}
\chapter
[graphs]
{
Representation of graphs
}
In this chapter we will peek into the area of data structures for representation of
graphs. Our ultimate goal is to design a data structure that represents a forest with
weighted vertices and allows efficient path queries (e.g. what is the
lightest edge
on the
path between
$
u
$
and
$
v
$
) along with
weigh
t and structural updates.
weighted vertices and allows efficient path queries (e.g. what is the
cheapest vertex
on the
path between
$
u
$
and
$
v
$
) along with
cos
t and structural updates.
Let us define the problem more formally. We wish to represent a forest
$
F
=
(
V,
E
)
$
, where each vertex~
$
v
$
has
weigh
t~
$
w
(
v
)
\in\R
$
.
\foot
{
We could also had weighted edges
E
)
$
, where each vertex~
$
v
$
has
cos
t~
$
c
(
v
)
\in\R
$
.
\foot
{
We could also had weighted edges
instead.
}
We would like to support following operations:
\tightlist
{
o
}
\:\em
{
path query
}
--- find the vertex with minimum
weigh
t on a path
$
u
\to
\:\em
{
path query
}
--- find the vertex with minimum
cos
t on a path
$
u
\to
v
$
;
\foot
{
Generally, we can use any associative operation instead of minimum.
}
\:\em
{
point update
}
--- set
$
w
(
v
)
\leftarrow
c
\in\R
$
;
\:\em
{
path update
}
--- increase
weigh
t of each vertex on path
$
u
\to
v
$
by
$
\delta\in\R
$
;
\:\em
{
structural update
}
--- connect
/disconnect
two trees via edge
$
(
u,v
)
$
.
\:\em
{
point update
}
--- set
$
c
(
v
)
\leftarrow
d
\in\R
$
;
\:\em
{
path update
}
--- increase
cos
t of each vertex on
the
path
$
u
\to
v
$
by
$
\delta\in\R
$
;
\:\em
{
structural update
}
--- connect two trees via edge
$
(
u,v
)
$
or delete edge
$
(
u,v
)
$
.
\endlist
...
...
@@ -31,9 +33,9 @@ As a warm-up we build a data structure for $F$ being a static path, without stru
updates. This will also be an important building block for the more general case.
Let us denote the vertices
$
v
_
1
,
\dots
, v
_
n
$
according to the position on the path and let
us denote
$
w
_
i
=
w
(
v
_
i
)
$
.
\TODO\foot
{
maybe change initial notation
}
We build an range
tree~
$
T
$
over the
weigh
ts
$
w
_
1
,
\dots
,
w
_
n
$
. That is,
$
T
$
is a complete binary tree with
$
w
_
1
,
\dots
w
_
n
$
in its leaves (in this order) and inner nodes contain the minimum of their
us denote
$
c
_
i
=
c
(
v
_
i
)
$
. We build an range
tree~
$
T
$
over the
cos
ts
$
c
_
1
,
\dots
,
c
_
n
$
. That is,
$
T
$
is a complete binary tree with
$
c
_
1
,
\dots
c
_
n
$
in its leaves (in this order) and inner nodes contain the minimum of their
children. Note that each node represents a subpath of~
$
F
$
with leaves being the single
vertices.
...
...
@@ -53,8 +55,8 @@ an interval of leaves of~$T$ and each such interval can be exactly covered by $\
subtrees and they can be easily found by traversing~
$
T
$
top to bottom. The answer to the
path query can then be easily calculated from the values in the roots of these subtrees.
The point update of
$
w
_
i
$
is simply a matter of recalculating values in the nodes on path
from root of~
$
T
$
to the leaf~
$
w
_
i
$
, so it takes
$
\O
(
\log
n
)
$
time.
The point update of
$
c
_
i
$
is simply a matter of recalculating values in the nodes on path
from root of~
$
T
$
to the leaf~
$
c
_
i
$
, so it takes
$
\O
(
\log
n
)
$
time.
The path updates are more tricky. As in the path query, we can decompose the update to
$
\O
(
\log
n
)
$
subtrees. But we cannot afford to recalculate the values in these subtrees
...
...
@@ -88,8 +90,8 @@ up, towards the root \NOTE\foot{maybe unnecessary now}.
\defn
{
Let~
$
F
$
be a rooted tree. For any vertex~
$
v
$
we define
$
s
(
v
)
$
to be the size of subtree
rooted at~
$
v
$
(including~
$
v
$
). Let~
$
u
$
be a child of~
$
v
$
, we say the edge~
$
(
v,u
)
$
is
\em
{
heavy
}
iff
$
s
(
u
)
\ge
s
(
v
)/
2
$
, otherwise we say
$
(
v,u
)
$
is
\em
{
light
}
. Finally, a
rooted at~
$
v
$
(including~
$
v
$
). Let~
$
u
$
be a child of~
$
v
$
, we say the edge~
$
(
u,v
)
$
is
\em
{
heavy
}
iff
$
s
(
u
)
\ge
s
(
v
)/
2
$
, otherwise we say
$
(
u,v
)
$
is
\em
{
light
}
. Finally, a
\em
{
heavy path
}
is simply a path containing only heavy edges.
}
...
...
@@ -161,7 +163,7 @@ A data structure based on heavy-light decomposition can perform \em{path queries
$
\O
(
n
)
$
time and requires
$
\O
(
n
)
$
space.
}
\subsection
{
Static
weigh
ts
}
\subsection
{
Static
cos
ts
}
Let us analyze the partitioning of a path in a bit more detail:
...
...
@@ -170,20 +172,93 @@ When we partition a path into $\O(\log n)$ heavy subpaths, all of the subpaths,
exception, are a prefix or a suffix of heavy path.
}
We can
mak
e this observation to make path queries faster but at the cost of keeping the
weigh
ts static and forgoing the path updates. For each heavy path we calculate and store
We can
us
e this observation to make path queries faster but at the cost of keeping the
cos
ts static and forgoing the path updates. For each heavy path we calculate and store
prefix and suffix minimums. This allows us to answer almost all subqueries in constant
time and the one remaining subquery can be answered in
$
\O
(
\log
n
)
$
.
\cor
{
On a static tree with static
weigh
ts, the path queries can be answered in
$
\O
(
\log
n
)
$
On a static tree with static
cos
ts, the path queries can be answered in
$
\O
(
\log
n
)
$
time.
}
\section
[linkcut]
{
Link-cut trees
}
\TODO
Link-cut trees are dynamic version of the heavy-light decomposition. They allow us to
change structure of the represented forest by either linking two trees or by cutting an
edge inside a tree. Link-cut trees were introduced in a paper by Sleator and Tarjan
\TODO
reference. However, we will show later version that uses splay trees instead of original
biased trees
\TODO
reference. Although it achieves the time complexity only in amortized
case, it is significantly easier to analyze.
Link-cut tree represents a forest
$
F
$
of
\em
{
rooted
}
trees; each edge is oriented towards the
respective root. It supports following operations:
\TODO
proper formatting
\list
{
o
}
\:
Structural queries:
\tightlist
{
-
}
\:
$
\opdf
{
Parent
}
(
v
)
$
;
\:
$
\opdf
{
Root
}
(
v
)
$
--- return root of
$
v
$
's tree
\endlist
\:
Structural updates:
\tightlist
{
-
}
\:
$
\opdf
{
Cut
}
(
v
)
$
--- remove an edge between
$
v
$
and
$
\op
{
Parent
}
(
v
)
$
;
\:
$
\opdf
{
Link
}
(
u,v
)
$
--- create edge
$
(
v,u
)
$
such that
$
v
$
becomes a child of
$
u
$
(
$
v
$
needs to be a root before the call of
$
\op
{
Link
}$
and both vertices cannot lie within
the same tree);
\:
$
\opdf
{
Evert
}
(
v
)
$
--- reroot the tree and make
$
v
$
the root
\endlist
\:
Cost queries:
\tightlist
{
-
}
\:
$
\opdf
{
Cost
}
(
v
)
$
;
\:
$
\opdf
{
PathMin
}
(
v
)
$
--- return minimum cost on the path
$
v
\to
\op
{
Root
}
(
v
)
$
\endlist
\:
Cost updates:
\tightlist
{
-
}
\:
$
\opdf
{
SetCost
}
(
v,x
)
$
;
\:
$
\opdf
{
PathUpdate
(
v,
\delta
)
}$
--- increase all costs on the path
$
v
\to
\op
{
Root
}
(
v
)
$
by
$
\delta
$
.
\endlist
\endlist
Link-cut trees use a similar approach as the heavy-light decomposition and each
tree is decomposed into a system of paths. Instead of heavy and light edges we have
\em
{
fat
}
and
\em
{
thin
}
edges. However, whether an edge is fat or thin is not given by the
structure of the tree but by the history of the data structure. The only requirement is
that every vertex has at most one incoming fat edge. This requirement assures that the
tree can be decomposed into a system of fat paths interconnected by thin edges. Unlike
heavy-light decomposition, we don't have bound on the number of thin edges on the path
$
v
\to
\Root
(
v
)
$
. In fact, it is possible that there are only thin edges in the tree!
Nevertheless, we will show that everything works out in the amortized case.
The key ingredient of our data structure is the
$
\opdf
{
Expose
}$
operation.
$
\Expose
(
v
)
$
changes the fat-thin decomposition in such a way that
$
v
$
and
$
\Root
(
v
)
$
are the endpoints
of a single fat path. Internally, all operations on trees are implemented using
$
\Expose
$
and
a constant number of operations on a fat path:
\list
{
-
}
\:
$
\Root
(
v
)
$
=
$
\Expose
(
v
)
$
, then return the top of the fat path;
\:
$
\op
{
Cut
}
(
v
)
$
=
$
\Expose
(
\Parent
(
u
))
$
, then remove thin edge;
\:
$
\op
{
Link
}
(
u,v
)
$
=
$
\Expose
(
u
)
$
, then join two fat paths;
\:
$
\op
{
Evert
}
(
v
)
$
=
$
\Expose
(
v
)
$
, then reverse fat path;
\:
$
\op
{
PathMin
}
(
v
)
$
=
$
\Expose
(
v
)
$
, then return path minimum for the fat path;
\:
$
\op
{
PathUpdate
}
(
v
)
$
=
$
\Expose
(
v
)
$
, then perform path update on the fat path.
\endlist
{}
Conceptually,
$
\Expose
(
v
)
$
is straightforward. Assume~
$
v
$
lies on a fat path~
$
A
$
. We start
at~
$
v
$
and jump along~
$
A
$
to its top~
$
t
$
. Unless
$
t
$
is the root of the tree (which means
we are done),
$
t
$
is connected to with a fat path~
$
B
$
via thin edge
$
(
t, p
)
$
, see
Figure~
\TODO
. We cut~
$
B
$
by turning fat edge below~
$
p
$
into a thin edge. Then we join top
half of~
$
B
$
with~
$
A
$
by making edge~
$
(
t, p
)
$
fat. Now we jump to the top of the newly
created fat path and repeat the whole process. In the end, we turn a fat edge below~
$
v
$
into thin edge (if there was one) and make~
$
v
$
the endpoint of the fat path.
\TODO
picture of one step of expose
The actual implementation of
$
\Expose
$
is, however, more tricky, due to our representation
paths and trees.
\subsection
[Representation of fat paths via splay trees]
\TODO
\section
{
Application: Faster Dinic's algorithm
}
\TODO
...
...
This diff is collapsed.
Click to expand it.
om-graphs/range-tree.ipe
+
9
−
9
View file @
c57e1f1c
<?xml version="1.0"?>
<!DOCTYPE ipe SYSTEM "ipe.dtd">
<ipe
version=
"70212"
creator=
"Ipe 7.2.13"
>
<info
created=
"D:20210528110052"
modified=
"D:20210
602150616
"
/>
<info
created=
"D:20210528110052"
modified=
"D:20210
803140920
"
/>
<ipestyle
name=
"basic"
>
<symbol
name=
"arrow/arc(spx)"
>
<path
stroke=
"sym-stroke"
fill=
"sym-stroke"
pen=
"sym-pen"
>
...
...
@@ -255,7 +255,7 @@ h
<page>
<layer
name=
"alpha"
/>
<view
layers=
"alpha"
active=
"alpha"
/>
<text
layer=
"alpha"
matrix=
"1 0 0 1 -80 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
11.602
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
w
_1
</text>
<text
layer=
"alpha"
matrix=
"1 0 0 1 -80 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
8.781
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
c
_1
</text>
<use
matrix=
"1 0 0 1 -80 -192"
name=
"mark/disk(sx)"
pos=
"288 768"
size=
"normal"
stroke=
"black"
/>
<use
matrix=
"1 0 0 1 -80 -192"
name=
"mark/disk(sx)"
pos=
"224 736"
size=
"normal"
stroke=
"black"
/>
<use
matrix=
"1 0 0 1 -80 -192"
name=
"mark/disk(sx)"
pos=
"352 736"
size=
"normal"
stroke=
"black"
/>
...
...
@@ -371,13 +371,13 @@ h
<text
matrix=
"1 0 0 1 -80 -192"
transformations=
"translations"
pos=
"336 624"
stroke=
"black"
type=
"label"
width=
"4.981"
height=
"6.42"
depth=
"0"
halign=
"center"
valign=
"center"
>
6
</text>
<text
matrix=
"1 0 0 1 -80 -192"
transformations=
"translations"
pos=
"368 624"
stroke=
"black"
type=
"label"
width=
"4.981"
height=
"6.42"
depth=
"0"
halign=
"center"
valign=
"center"
>
7
</text>
<text
matrix=
"1 0 0 1 -80 -192"
transformations=
"translations"
pos=
"400 624"
stroke=
"black"
type=
"label"
width=
"4.981"
height=
"6.42"
depth=
"0"
halign=
"center"
valign=
"center"
>
8
</text>
<text
matrix=
"1 0 0 1 -48 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
11.602
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
w
_2
</text>
<text
matrix=
"1 0 0 1 -16 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
11.602
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
w
_3
</text>
<text
matrix=
"1 0 0 1 16 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
11.602
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
w
_4
</text>
<text
matrix=
"1 0 0 1 48 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
11.602
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
w
_5
</text>
<text
matrix=
"1 0 0 1 80 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
11.602
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
w
_6
</text>
<text
matrix=
"1 0 0 1 112 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
11.602
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
w
_7
</text>
<text
matrix=
"1 0 0 1 144 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
11.602
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
w
_8
</text>
<text
matrix=
"1 0 0 1 -48 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
8.781
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
c
_2
</text>
<text
matrix=
"1 0 0 1 -16 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
8.781
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
c
_3
</text>
<text
matrix=
"1 0 0 1 16 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
8.781
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
c
_4
</text>
<text
matrix=
"1 0 0 1 48 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
8.781
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
c
_5
</text>
<text
matrix=
"1 0 0 1 80 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
8.781
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
c
_6
</text>
<text
matrix=
"1 0 0 1 112 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
8.781
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
c
_7
</text>
<text
matrix=
"1 0 0 1 144 -192"
transformations=
"translations"
pos=
"176 656"
stroke=
"black"
type=
"label"
width=
"
8.781
"
height=
"4.294"
depth=
"1.49"
halign=
"center"
valign=
"baseline"
style=
"math"
>
c
_8
</text>
<path
stroke=
"black"
>
176 520 m
152 472 l
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment