Skip to content

Commit dbdb322

Browse files
committed
Add tests for Sparse Table
1 parent a93dbdb commit dbdb322

File tree

2 files changed

+78
-7
lines changed

2 files changed

+78
-7
lines changed

src/data_structures/sparse-table.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ The size of the 2-dimensional array will be $\text{MAXN} \times (K + 1)$, where
3232
$\text{K}$ has to satisfy $\text{K} \ge \lfloor \log_2 \text{MAXN} \rfloor + 1$, because $2^{\lfloor \log_2 \text{MAXN} \rfloor}$ is the biggest power of two range, that we have to support.
3333
For arrays with reasonable length ($\le 10^7$ elements), $K = 25$ is a good value.
3434

35-
```cpp
35+
```cpp sparsetable_definition
3636
int st[MAXN][K + 1];
3737
```
3838

3939
Because the range $\[i, i + 2^j - 1\]$ of length $2^j$ splits nicely into the ranges $\[i, i + 2^{j - 1} - 1\]$ and $\[i + 2^{j - 1}, i + 2^j - 1\]$, both of length $2^{j - 1}$, we can generate the table efficiently using dynamic programming:
4040

41-
```cpp
41+
```cpp sparsetable_generation
4242
for (int i = 0; i < N; i++)
4343
st[i][0] = f(array[i]);
4444

@@ -58,7 +58,7 @@ For this type of queries, we want to find the sum of all values in a range.
5858
Therefore the natural definition of the function $f$ is $f(x, y) = x + y$.
5959
We can construct the data structure with:
6060

61-
```cpp
61+
```cpp sparsetable_sum_generation
6262
long long st[MAXN][K];
6363

6464
for (int i = 0; i < N; i++)
@@ -72,7 +72,7 @@ for (int j = 1; j <= K; j++)
7272
To answer the sum query for the range $\[L, R\]$, we iterate over all powers of two, starting from the biggest one.
7373
As soon as a power of two $2^j$ is smaller or equal to the length of the range ($= R - L + 1$), we process the first the first part of range $\[L, L + 2^j - 1\]$, and continue with the remaining range $\[L + 2^j, R\]$.
7474

75-
```cpp
75+
```cpp sparsetable_sum_query
7676
long long sum = 0;
7777
for (int j = K; j >= 0; j--) {
7878
if ((1 << j) <= R - L + 1) {
@@ -98,7 +98,7 @@ $$\min(\text{st}\[L\]\[j\], \text{st}\[R - 2^j + 1][j]) \quad \text{ where } j =
9898
This requires that we are able to compute $\log_2(R - L + 1)$ fast.
9999
You can accomplish that by precomputing all logarithms:
100100

101-
```cpp
101+
```cpp sparse_table_log_table
102102
int log[MAXN+1];
103103
log[1] = 0;
104104
for (int i = 2; i <= MAXN; i++)
@@ -107,7 +107,7 @@ for (int i = 2; i <= MAXN; i++)
107107

108108
Afterwards we need to precompute the Sparse Table structure. This time we define $f$ with $f(x, y) = \min(x, y)$.
109109

110-
```cpp
110+
```cpp sparse_table_minimum_generation
111111
int st[MAXN][K];
112112

113113
for (int i = 0; i < N; i++)
@@ -120,7 +120,7 @@ for (int j = 1; j <= K; j++)
120120

121121
And the minimum of a range $\[L, R\]$ can be computed with:
122122

123-
```cpp
123+
```cpp sparse_table_minimum_query
124124
int j = log[R - L + 1];
125125
int minimum = min(st[L][j], st[R - (1 << j) + 1][j]);
126126
```

test/test_sparsetable.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include <vector>
2+
#include <numeric>
3+
#include <cassert>
4+
5+
const int MAXN = 15;
6+
const int K = 5;
7+
8+
const int N = MAXN;
9+
const std::vector<int> array = {19, 16, 2, 15, 2, 12, 13, 13, 18, 14, 0, 4, 17, 17, 4};
10+
11+
void test_generic_sparsetable() {
12+
auto f = [&](int x, int y=0) { return x + y; };
13+
14+
#include "sparsetable_definition.h"
15+
#include "sparsetable_generation.h"
16+
17+
auto sum_query = [&](int L, int R) {
18+
#include "sparsetable_sum_query.h"
19+
return sum;
20+
};
21+
22+
for (int L = 0; L < N; L++) {
23+
for (int R = L; R < N; R++) {
24+
int sum = std::accumulate(array.begin() + L, array.begin() + R + 1, 0);
25+
assert(sum == sum_query(L, R));
26+
}
27+
}
28+
}
29+
30+
void test_range_sum_sparsetable() {
31+
#include "sparsetable_sum_generation.h"
32+
33+
auto sum_query = [&](int L, int R) {
34+
#include "sparsetable_sum_query.h"
35+
return sum;
36+
};
37+
38+
for (int L = 0; L < N; L++) {
39+
int sum = 0;
40+
for (int R = L; R < N; R++) {
41+
sum += array[R];
42+
assert(sum == sum_query(L, R));
43+
}
44+
}
45+
}
46+
47+
void test_range_minimum_sparsetable() {
48+
using std::min;
49+
50+
#include "sparse_table_log_table.h"
51+
#include "sparse_table_minimum_generation.h"
52+
53+
auto minimum_query = [&](int L, int R) {
54+
#include "sparse_table_minimum_query.h"
55+
return minimum;
56+
};
57+
58+
for (int L = 0; L < N; L++) {
59+
int minimum = array[L];
60+
for (int R = L; R < N; R++) {
61+
minimum = min(minimum, array[R]);
62+
assert(minimum == minimum_query(L, R));
63+
}
64+
}
65+
}
66+
67+
int main() {
68+
test_generic_sparsetable();
69+
test_range_sum_sparsetable();
70+
test_range_minimum_sparsetable();
71+
}

0 commit comments

Comments
 (0)