function build(values: number[], node: number, left: number, right: number) { if (left === right) {sums[node] = values[left]; return;
}
const middle = (left + right) >> 1;
build(values, 2 * node, left, middle); build(values, 2 * node + 1, middle + 1, right); sums[node] = sums[2 * node] + sums[2 * node + 1];
}
function query(node: number, left: number, right: number, from: number, to: number): number {// the sum of values[from..to], visiting only the nodes that straddle the ends
if (to < left || right < from) return 0;
if (from <= left && right <= to) return sums[node];
const middle = (left + right) >> 1;
return query(2 * node, left, middle, from, to) + query(2 * node + 1, middle + 1, right, from, to);
}
function update(node: number, left: number, right: number, index: number, value: number) { if (left === right) { sums[node] = value; return; }const middle = (left + right) >> 1; if (index <= middle) update(2 * node, left, middle, index, value); else update(2 * node + 1, middle + 1, right, index, value);
sums[node] = sums[2 * node] + sums[2 * node + 1];
}
Node [0, 7] splits at 3: build [0, 3] and [4, 7] first.
Understanding Segment tree
The idea
A segment tree puts the array at the leaves and gives every internal node the sum of its two children, so the root holds the total and each node owns a contiguous range. A range query starts at the root: a node fully inside the range contributes its sum in one step, a node fully outside contributes nothing, and only the nodes that straddle an end of the range recurse into their children.
At most two nodes per level straddle, so a query visits O(log n) nodes. A point update changes one leaf and recomputes the log n ancestors above it. Any associative operation works in place of the sum: minimum, maximum, gcd, or a matrix product.
The four stages
Complexity
Versus its siblings
Pseudocode
BUILD(node, left, right): a leaf holds its value; otherwise build both halves and store their sum
QUERY(node, left, right, from, to)
outside the query: 0 · fully inside: the node's sum · straddling: QUERY(left child) + QUERY(right child)
UPDATE(node, left, right, index, value): descend to the leaf, set it, recompute the sums on the way back up
When to use
Pitfalls
History
Jon Bentley introduced segment trees in 1977 for computational geometry, to count intersections of rectangles in a sweep line. The competitive-programming form with an implicit array, lazy propagation and arbitrary monoids grew out of the 2000s contest scene and is now the standard teaching example of a divide-and-conquer data structure.