What is a Segment Tree?
A Segment Tree answers a question that neither a plain array nor a running-total (prefix-sum) array handles well at the same time: "what's the sum (or min, max, gcd...) of elements from index l to r?", while also supporting fast updates to individual elements. A prefix-sum array answers range queries in O(1), but a single update forces you to recompute every prefix after it — O(n) per update. A segment tree gets both operations down to O(log n).
How Is It Built?
Every node in a segment tree represents a contiguous range of the underlying array. Leaves represent single elements; every internal node represents the union of its two children's ranges, and stores the combined result of some associative operation (sum, min, max, etc.) over that whole range — computed once and cached, not recomputed from scratch on every query.
How Does a Range Query Work?
A range query works by decomposing the query range into a small number of these pre-combined node ranges. Starting from the root, if a node's range falls entirely outside the query, it's skipped. If it falls entirely inside the query, its cached value is used directly — no need to look at its children at all. Only when a node's range partially overlaps the query does the search recurse into both children. This decomposition never needs more than O(log n) nodes to cover any range.
How Does a Point Update Work?
A point update walks straight from the root down to the one leaf that needs to change, updates it, and then recomputes each ancestor's cached value on the way back up — exactly one path of length O(log n), touching nothing else in the tree.
Algorithm Steps
- Build: recursively split [l, r] at its midpoint until reaching single-element leaves, then combine each pair of children's results going back up
- Range Query(ql, qr) on the current node's range [l, r]:
- If [l, r] is entirely outside [ql, qr], return the operation's identity (0 for sum) and stop
- If [l, r] is entirely inside [ql, qr], return this node's cached value directly
- Otherwise, recurse into both children and combine their results
- Point Update(index, value): descend to the leaf for that index, set its value, then recompute every ancestor's cached value on the way back up
Time Complexity
- Build: O(n) — every node is computed exactly once.
- Range Query: O(log n) — at most a constant number of nodes per level are visited.
- Point Update: O(log n) — exactly one root-to-leaf path is touched.