Competitive programming in Haskell: range queries, classified
Static range queries
Suppose we have a sequence of values, which is static in the sense that the values in the sequence will never change, and we want to perform range queries, that is, for various ranges we want to compute the total of all consecutive values in the range, according to some binary combining operation. For example, we might want to compute the maximum, sum, or product of all the consecutive values in a certain subrange. We have various options depending on the kind of ranges we want and the algebraic properties of the operation.
If we want ranges corresponding to a sliding window, we can use an amortized queue structure to find the total of each range in \(O(1)\), for an arbitrary monoid.
If we want arbitrary ranges but the operation is a group, the solution is relatively straightforward: we can precompute all prefix sums, and subtract to find the result for an arbitrary range in \(O(1)\). I will write about this in an upcoming blog post.
If the operation is an idempotent semigroup (that is, it has the property that \(x \diamond x = x\) for all \(x\)), we can use a sparse table, which takes \(O(n \lg n)\) time and space for precomputation, and then allows us to answer arbitrary range queries in \(O(1)\). I also plan to write about this in an upcoming blog post.
If the operation is an arbitrary monoid, we can use a sqrt tree, which uses \(O(n \lg \lg n)\) precomputed time and space, and allows answering arbitrary range queries in \(O(\lg \lg n)\). I will write about this in a future post.
Dynamic range queries
What if we want dynamic range queries, that is, we want to be able to interleave range queries with arbitrary updates to the values of the sequence?
- If the operation is an arbitrary monoid, we can use a segment tree.
- If the operation is a group, we can use a Fenwick tree.
I published a paper about Fenwick trees, which also discusses segment trees, but I should write more about them here!
Table
Here’s a table summarizing the above classification scheme. I plan to fill in links as I write blog posts about each row.
Sequence | Ranges | Operation | Solution | Precomputation | Queries |
---|---|---|---|---|---|
Static | Sliding window | Monoid | Amortized queue | \(O(1)\) | \(O(1)\) |
Static | Arbitrary | Group | Prefix sum table | \(O(n)\) | \(O(1)\) |
Static | Arbitrary | Idempotent semigroup | Sparse table | \(O(n \lg n)\) | \(O(1)\) |
Static | Arbitrary | Monoid | Sqrt table | \(O(n \lg \lg n)\) | \(O(\lg \lg n)\) |
Dynamic | Arbitrary | Group | Fenwick tree | \(O(n)\) | \(O(\lg n)\) |
Dynamic | Arbitrary | Monoid | Segment tree | \(O(n)\) | \(O(\lg n)\) |