« Monads are not like burritos

Competitive programming in Haskell: range queries, classified

Posted on June 23, 2025
Tagged , , , , ,

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)\)