-
Notifications
You must be signed in to change notification settings - Fork 62
/
sparseTable.cpp
140 lines (120 loc) · 4.95 KB
/
sparseTable.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <array> /// for std::array
#include <cassert> /// for assert
#include <iostream> /// for IO operations
/**
* @namespace data_structures
* @brief Data Structures algorithms
*/
namespace data_structures {
/**
* @namespace sparse_table
* @brief Functions for Implementation of [Sparse
* Table](https://brilliant.org/wiki/sparse-table/)
*/
namespace sparse_table {
/**
* @brief A struct to represent sparse table for `min()` as their invariant
* function, for the given array `A`. The answer to queries are stored in the
* array ST.
*/
constexpr uint32_t N = 12345; ///< the maximum size of the array.
constexpr uint8_t M = 14; ///< ceil(log2(N)).
struct Sparse_table {
size_t n = 0; ///< size of input array.
/** @warning check if `N` is not less than `n`. if so, manually increase the
* value of N */
std::array<int64_t, N> A = {}; ///< input array to perform RMQ.
std::array<std::array<int64_t, N>, M>
ST{}; ///< the sparse table storing `min()` values for given interval.
std::array<int64_t, N> LOG = {}; ///< where floor(log2(i)) are precomputed.
/**
* @brief Builds the sparse table for computing min/max/gcd/lcm/...etc
* for any contiguous sub-segment of the array.This is an example of
* computing the index of the minimum value.
* @return void
* @complexity: O(n.log(n))
*/
void buildST() {
LOG[0] = -1;
for (size_t i = 0; i < n; ++i) {
ST[0][i] = static_cast<int64_t>(i);
LOG[i + 1] = LOG[i] + !(i & (i + 1)); ///< precomputing `log2(i+1)`
}
for (size_t j = 1; static_cast<size_t>(1 << j) <= n; ++j) {
for (size_t i = 0; static_cast<size_t>(i + (1 << j)) <= n; ++i) {
/**
* @note notice how we deal with the range of length `pow(2,i)`,
* and we can reuse the computation that we did for the range of
* length `pow(2,i-1)`.
*
* So, ST[j][i] = min( ST[j-1][i], ST[j-1][i + pow(2,j-1)]).
* @example ST[2][3] = min(ST[1][3], ST[1][5])
*/
int64_t x = ST[j - 1][i]; ///< represents minimum value over
///< the range [j,i]
int64_t y =
ST[j - 1]
[i + (1 << (j - 1))]; ///< represents minimum value over
///< the range [j,i + pow(2,j-1)]
ST[j][i] =
(A[x] <= A[y] ? x : y); ///< represents minimum value over
///< the range [j,i]
}
}
}
/**
* @brief Queries the sparse table for the value of the interval [l, r]
* (i.e. from l to r inclusive).
* @param l the left index of the range (inclusive).
* @param r the right index of the range (inclusive).
* @return the computed value of the given interval.
* @complexity: O(1)
*/
int64_t query(int64_t l, int64_t r) {
int64_t g = LOG[r - l + 1]; ///< smallest power of 2 covering [l,r]
int64_t x = ST[g][l]; ///< represents minimum value over the range
///< [g,l]
int64_t y =
ST[g][r - (1 << g) + 1]; ///< represents minimum value over the
///< range [g, r - pow(2,g) + 1]
return (A[x] <= A[y] ? x : y); ///< represents minimum value over
///< the whole range [l,r]
}
};
} // namespace sparse_table
} // namespace data_structures
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
/* We take an array as an input on which we need to perform the ranged
* minimum queries[RMQ](https://en.wikipedia.org/wiki/Range_minimum_query).
*/
std::array<int64_t, 10> testcase = {
1, 2, 3, 4, 5,
6, 7, 8, 9, 10}; ///< array on which RMQ will be performed.
size_t testcase_size =
sizeof(testcase) / sizeof(testcase[0]); ///< size of self test's array
data_structures::sparse_table::Sparse_table
st{}; ///< declaring sparse tree
std::copy(std::begin(testcase), std::end(testcase),
std::begin(st.A)); ///< copying array to the struct
st.n = testcase_size; ///< passing the array's size to the struct
st.buildST(); ///< precomputing sparse tree
// pass queries of the form: [l,r]
assert(st.query(1, 9) == 1); ///< as 1 is smallest from 1..9
assert(st.query(2, 6) == 2); ///< as 2 is smallest from 2..6
assert(st.query(3, 8) == 3); ///< as 3 is smallest from 3..8
std::cout << "Self-test implementations passed!" << std::endl;
}
/**
* @brief Main function
* @param argc commandline argument count (ignored)
* @param argv commandline array of arguments (ignored)
* @returns 0 on exit
*/
int main(int argc, char *argv[]) {
test(); // run self-test implementations
return 0;
}