Skip to content

Commit 670b0bb

Browse files
algmyrjakobkogler
authored andcommitted
Fix section depth (cp-algorithms#333)
1 parent 5f8d932 commit 670b0bb

File tree

3 files changed

+15
-15
lines changed

3 files changed

+15
-15
lines changed

src/data_structures/sqrt-tree.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ Also we have some queries $q(l, r)$. For each query, we need to compute $a_l \ci
1010

1111
Sqrt Tree can process such queries in $O(1)$ time with $O(n \cdot \log \log n)$ preprocessing time and $O(n \cdot \log \log n)$ memory.
1212

13-
# Description
13+
## Description
1414

15-
## Building sqrt decomposition
15+
### Building sqrt decomposition
1616

1717
Let's make a [sqrt decomposition](/data_structures/sqrt_decomposition.html). We divide our array in $\sqrt{n}$ blocks, each block has size $\sqrt{n}$. For each block, we compute:
1818

@@ -55,7 +55,7 @@ We already can answer some queries using these arrays. If the query doesn't fit
5555

5656
But if we have queries that entirely fit into one block, we cannot process them using these three arrays. So, we need to do something.
5757

58-
## Making a tree
58+
### Making a tree
5959

6060
We cannot answer only the queries that entirely fit in one block. But what **if we build the same structure as described above for each block?** Yes, we can do it. And we do it recursively, until we reach the block size of $1$ or $2$. Answers for such blocks can be calculated easily in $O(1)$.
6161

@@ -67,7 +67,7 @@ Now we can answer the queries in $O(\log \log n)$. We can go down on the tree un
6767

6868
OK, now we can do $O(\log \log n)$ per query. Can it be done faster?
6969

70-
## Optimizing the query complexity
70+
### Optimizing the query complexity
7171

7272
One of the most obvious optimization is to binary search the tree node we need. Using binary search, we can reach the $O(\log \log \log n)$ complexity per query. Can we do it even faster?
7373

@@ -100,23 +100,23 @@ For more details, see the code below.
100100

101101
So, using this, we can answer the queries in $O(1)$ each. Hooray! :)
102102

103-
# Updating elements
103+
## Updating elements
104104

105105
We can also update elements in Sqrt Tree. Both single element updates and updates on a segment are supported.
106106

107-
## Updating a single element
107+
### Updating a single element
108108

109109
Consider a query $\text{update}(x, val)$ that does the assignment $a_x = val$. We need to perform this query fast enough.
110110

111-
### Naive approach
111+
#### Naive approach
112112

113113
First, let's take a look of what is changed in the tree when a single element changes. Consider a tree node with length $l$ and its arrays: $\text{prefixOp}$, $\text{suffixOp}$ and $\text{between}$. It is easy to see that only $O(\sqrt{l})$ elements from $\text{prefixOp}$ and $\text{suffixOp}$ change (only inside the block with the changed element). $O(l)$ elements are changed in $\text{between}$. Therefore, $O(l)$ elements in the tree node are updated.
114114

115115
We remember that any element $x$ is present in exactly one tree node at each layer. Root node (layer $0$) has length $O(n)$, nodes on layer $1$ have length $O(\sqrt{n})$, nodes on layer $2$ have length $O(\sqrt{\sqrt{n}})$, etc. So the time complexity per update is $O(n + \sqrt{n} + \sqrt{\sqrt{n}} + \dots) = O(n)$.
116116

117117
But it's too slow. Can it be done faster?
118118

119-
### An sqrt-tree inside the sqrt-tree
119+
#### An sqrt-tree inside the sqrt-tree
120120

121121
Note that the bottleneck of updating is rebuilding $\text{between}$ of the root node. To optimize the tree, let's get rid of this array! Instead of $\text{between}$ array, we store another sqrt-tree for the root node. Let's call it $\text{index}$. It plays the same role as $\text{between}$— answers the queries on segments of blocks. Note that the rest of the tree nodes don't have $\text{index}$, they keep their $\text{between}$ arrays.
122122

@@ -134,15 +134,15 @@ Note that the query complexity is still $O(1)$: we need to use $\text{index}$ in
134134

135135
So, total time complexity for updating a single element is $O(\sqrt{n})$. Hooray! :)
136136

137-
## Updating a segment
137+
### Updating a segment
138138

139139
Sqrt-tree also can do things like assigning an element on a segment. $\text{massUpdate}(x, l, r)$ means $a_i = x$ for all $l \le i \le r$.
140140

141141
There are two approaches to do this: one of them does $\text{massUpdate}$ in $O(\sqrt{n}\cdot \log \log n)$, keeping $O(1)$ per query. The second one does $\text{massUpdate}$ in $O(\sqrt{n})$, but the query complexity becomes $O(\log \log n)$.
142142

143143
We will do lazy propagation in the same way as it is done in segment trees: we mark some nodes as _lazy_, meaning that we'll push them when it's necessary. But one thing is different from segment trees: pushing a node is expensive, so it cannot be done in queries. On the layer $0$, pushing a node takes $O(\sqrt{n})$ time. So, we don't push nodes inside queries, we only look if the current node or its parent are _lazy_, and just take it into account while performing queries.
144144

145-
### First approach
145+
#### First approach
146146

147147
In the first approach, we say that only nodes on layer $1$ (with length $O(\sqrt{n}$) can be _lazy_. When pushing such node, it updates all its subtree including itself in $O(\sqrt{n}\cdot \log \log n)$. The $\text{massUpdate}$ process is done as follows:
148148

@@ -164,7 +164,7 @@ So we can do $\text{massUpdate}$ fast. But how lazy propagation affects queries?
164164

165165
The query complexity still remains $O(1)$.
166166

167-
### Second approach
167+
#### Second approach
168168

169169
In this approach, each node can be _lazy_ (except root). Even nodes in $\text{index}$ can be _lazy_. So, while processing a query, we have to look for _lazy_ tags in all the parent nodes, i. e. query complexity will be $O(\log \log n)$.
170170

@@ -182,7 +182,7 @@ But $\text{massUpdate}$ becomes faster. It looks in the following way:
182182

183183
Note that when we do the recursive call, we do prefix or suffix $\text{massUpdate}$. But for prefix and suffix updates we can have no more than one partially covered child. So, we visit one node on layer $1$, two nodes on layer $2$ and two nodes on any deeper level. So, the time complexity is $O(\sqrt{n} + \sqrt{\sqrt{n}} + \dots) = O(\sqrt{n})$. The approach here is similar to the segment tree mass update.
184184

185-
# Implementation
185+
## Implementation
186186

187187
The following implementation of Sqrt Tree can perform the following operations: build in $O(n \cdot \log \log n)$, answer queries in $O(1)$ and update an element in $O(\sqrt{n})$.
188188

src/graph/mpm.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
MPM (Malhotra, Pramodh-Kumar and Maheshwari) algorithm solves the maximum flow problem in $O(V^3)$. This algorithm is similar to [Dinic's algorithm](./graph/dinic.html).
55

6-
# Algorithm
6+
## Algorithm
77

88
Like Dinic's algorithm, MPM runs in phases, during each phase we find the blocking flow in the layered network of the residual network of $G$.
99
The main difference from Dinic's is how we find the blocking flow.
@@ -32,7 +32,7 @@ Each phase works in $O(V^2)$ because there are at most $V$ iterations (because a
3232
Summing, we get $O(V^2 + E) = O(V^2)$.
3333
Since there are less than $V$ phases (see the proof [here](./graph/dinic.html)), MPM works in $O(V^3)$ total.
3434

35-
# Implementation
35+
## Implementation
3636

3737
```cpp mpm
3838
struct MPM{

src/sequences/k-th.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Given an array __A__ of size __N__ and a number __K__. The challenge is to find
66

77
The basic idea - to use the idea of quick sort algorithm. Actually, the algorithm is simple, it is more difficult to prove that it runs in an average of O(N), in contrast to the quick sort.
88

9-
# Implementation (not recursive):
9+
## Implementation (not recursive):
1010

1111
```cpp
1212
template <class T>

0 commit comments

Comments
 (0)