Segment Trees: Efficient Range Queries

A segment tree is a balanced binary tree over an array that answers range queries (sum, min, max, gcd) and point/range updates in time after construction. Key result: any associative operation can be aggregated over a contiguous range by combining precomputed canonical segments. Used in competitive programming, computational geometry, and database range aggregation. Folklore data structure formalized through the 1970s–1980s (Bentley, de Berg et al.).

A segment tree stores aggregate information about every interval of an array in a hierarchical fashion: the root covers , and each internal node splits its interval into two halves stored in its children, down to leaves covering single elements. Because any query interval decomposes into of these canonical node-intervals, queries and updates run in logarithmic time. This matters because naive range queries cost per query while a precomputed prefix-sum array cannot handle updates efficiently — the segment tree handles both in . The surprising fact: the same skeleton supports radically different problems (range minimum, range sum, range gcd, range assignment with lazy propagation, even geometric "stabbing" queries) simply by changing the merge operation, as long as it is associative.

The Core Insight

A contiguous range over a power-of-two-aligned binary subdivision is the disjoint union of at most maximal aligned subintervals (canonical segments). Precompute the aggregate of every aligned subinterval once; then any query is the merge of a logarithmic number of these stored aggregates. The merge must be associative so the order of combination is irrelevant.

Formal Statement

Segment Tree

Let be an array with values in a set equipped with an associative binary operation (a semigroup; a monoid if an identity exists). The segment tree is a binary tree where each node is labeled with an interval and a stored aggregate

1
⟳define the aggregate of a node as the fold of its interval; leaves have so .

The root has interval . Each internal node with interval and midpoint has children covering and , giving the recurrence

2
⟳associativity lets the fold over split at into the fold of followed by that of .

In the array-based ("heap-indexed") implementation, node is the root, and node has children and . The array requires size at most :

3
⟳round up to the next power of two ; a complete binary tree with leaves has nodes.

Query Decomposition

For any query interval , the set of nodes selected by the standard recursive query forms a partition of into canonical segments, and the number of such nodes is at most . Hence a query costs

4
⟳at each tree depth the query frontier contains at most two "boundary" nodes that recurse further; all others are fully inside or fully outside and terminate.

Point Update

Updating a single element requires recomputing along the root-to-leaf path through the leaf for index , a path of length , so point update costs .

Why It Holds

Query runs in $O(\log n)$

We bound the number of nodes visited by the recursive query query(v, l, r) which returns the aggregate of .

  1. Three cases per node. At node with interval : (a) if , return identity and stop; (b) if , return and stop (a canonical segment); (c) otherwise recurse into both children and merge.
  1. Counting boundary nodes. Case (c) occurs only when straddles a query endpoint, i.e. contains but not all of , or contains . Consider the path tracking : at each level the half containing may split further (case c), while the other half is either fully inside (case b, stops) or fully outside (case a, stops). So along the left boundary at most one node per level recurses; same for the right boundary.
  1. Per-level bound. Hence at each of the levels () at most two nodes are in case (c), and each contributes at most two stopping children. The total visited nodes is .

Correctness via associativity

The returned value of query(v,l,r) equals , by induction on subtree height. Base: a leaf or a fully-inside node returns its stored fold, correct by . Inductive step: a straddling node returns ; since the left and right index sets are disjoint and their union is , associativity (and, where used, commutativity is not required because the canonical segments are concatenated in left-to-right order) gives the full fold.

Associativity alone suffices only if you merge canonical segments left-to-right in index order. If your merge is not commutative (e.g. matrix multiplication, string concatenation, function composition), you must preserve order when combining the left-subtree result with the right-subtree result. Swapping them silently breaks correctness.

Building Intuition

Think of the array as a ruler marked at every position. A segment tree is the set of all aligned "rulers within rulers": the whole thing, its two halves, their four quarters, and so on. To measure any contiguous stretch, you don't measure unit by unit — you greedily snap to the largest pre-measured aligned chunk that fits, then handle the leftover at both ends. Because halving the interval reaches a single element in steps, you never need more than a couple of chunks per level. The tree "pre-pays" the cost of aggregation so that queries become cheap lookups plus a logarithmic stitching step.

:::svg[Segment tree over array A=[5,2,7,1] showing canonical segments for query sum over [1,3)] Segment Tree: sum query on [1,3) selects two canonical nodes [0,4)=15 [0,2)=7 [2,4)=8 [0,1)=5 [1,2)=2 [2,3)=7 [3,4)=1 Answer = 2 + 7 = 9 (golden = canonical segments) Only O(log n) nodes touched, not the whole range

Worked Examples

Range Sum Query with a Point Update

Given: , monoid . Build: leaves ; internals , ; root . Query :
  1. Root straddles → recurse.
  2. Left straddles → recurse; right straddles → recurse.
  3. From left subtree: outside (drop), inside → take.
  4. From right subtree: inside → take, outside (drop).
  5. Merge in order: (canonical segments: ).
Update (was ):
  • Walk leaf : set to .
  • Recompute parent .
  • Recompute root .

Re-query (units: pure integer sum).

Range Minimum Query

Given: , semigroup . Build (midpoints split unevenly for ): root , children and .
  • : ; : ; root .
Query :
  1. Root straddles → recurse.
  2. straddles : taken; inside → take. Subresult .
  3. straddles : splits → , both inside; outside. Subresult .
  4. Merge: .

Verify directly: . ✓ (Note is idempotent and commutative, so even overlapping segments would be safe — a property exploited by the sparse table variant.)

Common Misconceptions

Segment tree vs. Binary Indexed Tree (Fenwick). A Fenwick tree is smaller and faster in constant factor but supports a narrower class of operations (cleanly invertible, like sum/xor) and is awkward for or arbitrary monoids. The segment tree is strictly more general — at the cost of – memory and constant factor. Do not assume they are interchangeable for range-min-with-updates.

Non-associative merge fails

Suppose you try to maintain "the value of the second-largest distinct element" of each interval as the merge. This operation is not associative: knowing the top-2 of and the top-2 of does not determine the second-largest of from a single scalar — you must store enough state (here, the top-2 multiset). The lesson: if your query function is non-associative, you must enlarge the node label to a structure that is associative under a well-defined merge, or the tree gives wrong answers.

Lazy propagation is mandatory for fast range updates. A point-update tree handles "add to one element" in , but "add to all of " naively costs . Lazy propagation stores a pending update at each node and pushes it down only when needed, restoring . Forgetting to push down before recursing into children is the single most common implementation bug.

Connections

The segment tree generalizes the Prefix Sum Array (which gives range sum but update) by trading a factor on queries for cheap updates. It is the dynamic cousin of the Sparse Table (which gives idempotent range queries but no updates). Its merge structure is precisely a Monoid homomorphism over intervals, linking it to algebraic Semigroup theory. Geometrically, the interval tree and segment tree of Computational Geometry solve stabbing and windowing queries using the same canonical-decomposition principle. The lazy-propagation variant relates to Amortized Analysis and the potential method.

Real-World Applications

  1. Competitive programming / algorithm contests — range sum/min/max/gcd with updates is a staple (Codeforces, ICPC).
  2. Database range aggregation — OLAP-style "sum of sales in a date range" with frequent inserts maps to lazy segment trees over time-indexed arrays.
  3. Computational geometry (windowing queries) — segment trees over -coordinates answer "which rectangles contain a vertical query line," used in CAD and VLSI design-rule checks.
  4. Genomics / sequence analysis — range GCD or range maximum over coverage arrays to find peaks in read-depth signals.
  5. Network traffic monitoring — sliding-window maxima of packet rates implemented via segment trees or their monotonic-queue cousins.
  6. Image processing — 2D segment trees (or Fenwick) for sub-rectangle sums in integral-image-with-updates pipelines.
  7. Financial time series — range-min/max over price windows for drawdown and high/low band computation with streaming updates.

Historical Development

  • 1972 — Range query problems formalized within early data-structure research; prefix sums and partial-sum tables already standard.
  • 1977 — Jon Bentley introduces the divide-and-conquer "tournament"/segment ideas; the maximum-subarray and range-aggregate framing emerge.
  • 1980 — Segment trees appear explicitly in computational geometry for interval stabbing and the measure problem (Klee's measure problem solutions).
  • 1985 — Fenwick-style implicit cumulative structures and balanced interval trees mature; Bentley & Ottmann sweep-line algorithms use segment-tree-like structures.
  • 1994 — Peter Fenwick publishes the Binary Indexed Tree, the lightweight specialization for cumulative frequency.
  • 1997 — de Berg, van Kreveld, Overmars, Schwarzkopf codify segment trees and interval trees in Computational Geometry: Algorithms and Applications, the canonical textbook treatment.
  • 2000s — Lazy propagation and "merge sort tree" / persistent segment tree variants become widely taught through competitive programming communities.
  • 2010s — Persistent and iterative (bottom-up) segment trees, plus the "Li Chao tree" for convex-hull-trick queries, become standard repertoire.

Subtleties & Limits

What is the true cost frontier? For semigroup range queries with updates, per operation is optimal in the comparison/algebraic model under reasonable assumptions, but constant-factor and cache-behavior optimization remains an engineering frontier (iterative bottom-up trees, SIMD-friendly layouts, van Emde Boas memory orderings). In the static idempotent case, sparse tables achieve query — and for general semigroups the disjoint sparse table also reaches query with build, showing the update-vs-query tradeoff is fundamental rather than incidental. The genuinely open territory lies in higher dimensions: -dimensional range queries with updates cost , and whether the poly-log exponent can be reduced for specific monoids (e.g. via fractional cascading or word-RAM tricks) is an active question. Persistence adds another axis: how cheaply can one support time-travel queries with bounded total memory?

See Also

Prefix Sum Array · Fenwick Tree · Sparse Table · Lazy Propagation · Monoid · Persistent Data Structures · Computational Geometry · Binary Trees

Before this

Where this leads