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:

  1. Let .
  2. 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.
  3. 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;
}