Introduction
It is well known that a segment tree can answer queries for information over an interval, such as the maximum subarray sum, a range sum, or the product of matrices on an interval.
However, ordinary segment-tree range queries may still be too slow in some situations.
In brief, building a segment tree requires merge operations, while each range query requires merge operations. The latter is acceptable for a range sum, but when the queried information is a linear basis whose merge costs , even merges can sometimes be too slow.
A “cat tree” is a static segment tree that does not support updates and only supports fast range queries.
Building such a static segment tree requires merge operations, but a query then needs only merge operations.
For special information such as a linear basis, the complexity can even be reduced to .
Principle
To query the information on , find the LCA in the segment tree of the nodes representing and . Let this node be , and let its interval be . We have two useful properties:
-
The interval contains . This is immediate because it is an ancestor of both and .
-
The interval crosses the midpoint of . Since is the LCA of and , the left child of is an ancestor of but not of , while the right child of is an ancestor of but not of . Therefore, lies in and lies in .
With these two properties, the query complexity can be reduced to .
Implementation
More specifically, when building the tree, let a segment-tree node represent .
Unlike a traditional segment tree, which stores only the sum on at this node, we additionally store the suffix sums on and the prefix sums on .
The construction complexity is . Similarly, the space complexity increases from to .
The query is the key part.
If the queried interval is , find the LCA of the nodes representing and , denoted by .
By the two properties above, are inside the interval represented by and cross the midpoint of .
This gives the crucial fact that, using the prefix and suffix sums stored at , we can split into , and then combine them to obtain the interval .
This process requires only merge operations.
But there seems to be a missing detail.
Finding the LCA does not itself appear to take time: a brute-force search takes , binary lifting takes , and converting to an ST table has too much overhead…
Heap-style construction
Specifically, pad the sequence to a power of and then build the segment tree.
The LCA index of two segment-tree nodes is the longest common prefix (LCP) of their binary indices.
It is easy to see that for the binary representations of and , lcp(x,y)=x>>digits[x^y]. Here digits[x] denotes the number of bits in , namely .
Thus, precomputing a digits array lets us find LCAs easily.
This constructs a cat tree.
When building the tree, we compute prefix and suffix sums. For a linear basis, whose merge costs but whose prefix sum costs , a cat tree improves the complexity of a static range-linear-basis structure from to .
References
- immortalCO's blog
- [Kle77] V. Klee, "Can the Measure of be Computed in Less than O (n log n) Steps?," Am. Math. Mon., vol. 84, no. 4, pp. 284–285, Apr. 1977.
- [BeW80] Bentley and Wood, "An Optimal Worst Case Algorithm for Reporting Intersections of Rectangles," IEEE Trans. Comput., vol. C–29, no. 7, pp. 571–577, Jul. 1980.