The Wavelet Tree is a data structure that maintains an array of integers by maintaining the Wavelet Matrix of the array.
The Wavelet Matrix is an matrix constructed in the following way:
- Let .
- For , is obtained by sorting using the -th bit in the binary representation as the primary key and the original order in as the secondary key.
- Set to if the -th bit of is , and otherwise.
In addition,
is also maintained.
This costs a space of .
Lemma
For any contiguous segment
the sequence formed by the values in this segment with the -th bit equal to is
and the sequence formed by the values with the -th bit equal to is
Build
Build builds a Wavelet Tree for in time and space.
Algorithm
Applying the definition to find yields an algorithm that solves the problem in time and space.
void build(int n, int m, std::vector<int> a) {
s.assign(m, std::vector(n + 1, 0));
for (int i = m - 1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
s[i][j + 1] = s[i][j] + !(a[j] >> i & 1);
}
std::ranges::stable_partition(a, [&](int x) -> bool {
return !(x >> i & 1);
});
}
}Range Kth Query
Range Kth Query finds the -th smallest element among in time and space.
Algorithm
Consider finding the -th smallest element among , given that
- If , the -th bit of the -th smallest element must be . Therefore, applying the lemma yields that the -th smallest element is equal to the -th smallest element among . Solve for it recursively.
- Otherwise, the -th bit of the -th smallest element must be . Therefore, applying the lemma yields that the -th smallest element is equal to the -th smallest element among . Solve for it recursively.
This algorithm solves the problem in time and space.
int range_kth_query(int l, int r, int k) {
int res = 0;
for (int i = m - 1; i >= 0; i--) {
if (k < s[i][r] - s[i][l]) {
l = s[i][l];
r = s[i][r];
} else {
res |= 1 << i;
k -= s[i][r] - s[i][l];
l += s[i][n] - s[i][l];
r += s[i][n] - s[i][r];
}
}
return res;
}Range Rank Query
Range Rank Query counts the number of elements less than among in time and space.
Algorithm
Consider counting the number of elements less than among , given that
- If the -th bit of is , all the elements with the -th bit equal to are greater than . Therefore, applying the lemma yields that the number of elements less than is equal to the number of elements less than among . Solve for it recursively.
- Otherwise, all the elements with the -th bit equal to are less than . Therefore, applying the lemma yields that the number of elements less than is equal to the number of elements with the -th bit equal to plus the number of elements less than among . Solve for it recursively.
This algorithm solves the problem in time and space.
int range_rank_query(int l, int r, int x) {
int res = 0;
for (int i = m - 1; i >= 0; i--) {
if (!(x >> i & 1)) {
l = s[i][l];
r = s[i][r];
} else {
res += s[i][r] - s[i][l];
l += s[i][n] - s[i][l];
r += s[i][n] - s[i][r];
}
}
return res;
}