A recursive structure over the value range rather than the index range. It answers rank, select, quantile and range-count queries in using bits — succinct enough to fit datasets a segment tree could not.
The construction
Split the value range at its midpoint. Partition the sequence stably into elements (left) and (right), and record for each position a bit saying which side it went to. Store a rank structure (prefix sums) over those bits, then recurse on each half.
values: 3 1 4 1 5 9 2 6 range [1,9], mid = 5
bits: 0 0 0 0 0 1 0 1
left: 3 1 4 1 5 2 range [1,5]
right: 9 6 range [6,9]
Depth , one bit per element per level → bits.
The core primitive
rank(i) on a level’s bit vector = “how many of the first elements went left”. With prefix sums this is , and it lets you map an index range at one level to the corresponding range at either child:
- left child:
- right child:
Every query is a walk down the tree, remapping the range at each step.
What it answers
| Query | Method | Cost |
|---|---|---|
| -th smallest in | descend: if (count going left), go left, else subtract and go right | |
| Count of elements in | descend, accumulating whole left subtrees | |
| Count of elements in in | difference of two counts | |
| rank: occurrences of in | descend to ‘s leaf | |
| select: position of the -th occurrence of | descend to the leaf, then walk back up | |
| Sum of elements in | store prefix sums per level as well | |
| Number of distinct values in | ✘ — needs a different structure |
Comparison for “-th smallest in a range”
| Structure | Build | Query | Memory | Online | Updates |
|---|---|---|---|---|---|
| Sort the range | — | ✔ | ✔ | ||
| Merge sort tree + binary search | ✔ | ✘ | |||
| Persistent segment tree | ints | ✔ | ✘ | ||
| Wavelet tree | bits | ✔ | ✘ | ||
| Mo’s + a value BIT | — | ✘ | ✘ | ||
| Offline BIT sweep | — | am. | ✘ | ✔ |
The persistent segment tree is the more common contest choice — the code is shorter and most people already have a persistent segtree template. The wavelet tree’s advantage is memory: bits instead of integers, a 32-64× saving, which matters for very large .
Where wavelet trees really live
They come from succinct data structures and text indexing:
- FM-index — a compressed full-text index built on the Burrows-Wheeler transform, with a wavelet tree providing the rank queries. This is what modern DNA aligners (BWA, Bowtie) use.
- Compressed suffix arrays.
- Document retrieval — “which documents contain this pattern”.
- Range median / quantile in large datasets, where memory is the binding constraint.
Updates
Not supported in the plain version — the bit vectors would need re-partitioning. A wavelet matrix (a flattened variant with better cache behaviour) has the same limitation. If you need updates, use an offline sweep or a sqrt decomposition over values.
See also: Persistent Structures · Merge Sort Tree · K-th Order Statistics