TREES, TRIES & HEAPS / ALGORITHM BRIEF

Segment tree

A segment tree is a binary tree over array ranges.

AdvancedPhase 04 / Topic 7 of 8Mental modelComplexityEdge cases
01

Overview

A segment tree is a binary tree over array ranges. The root covers [0, n - 1], each node covers a range and stores an aggregate of it (sum, min, max, gcd), and each leaf covers one element. Any range query is answered by combining O(log n) nodes, and updating one element changes only the O(log n) nodes on its path to the root.

It is the go-to structure when an array receives both updates and range queries mixed together, where prefix sums (O(n) per update) fail. With lazy propagation, it also supports range updates like 'add 5 to every element in [l, r]' in O(log n).

A company reporting structure

Each manager knows the total sales of their team. To get the sales of several teams, the CEO asks a few managers rather than every employee. When one employee makes a sale, only their manager chain up to the CEO needs updating.

02

When to use it

  • Range sum / min / max / gcd queries with point updates interleaved.
  • Range updates and range queries together (lazy propagation).
  • Counting problems after coordinate compression (count smaller elements).
  • Any associative combine operation over ranges.
03

Problem patterns it solves

Point update, range query

Recognize it when: update(i, val) and sumRange(l, r) interleaved.

  • 307. Range Sum Query - Mutable
  • 2407. Longest Increasing Subsequence II
Range minimum / maximum

Recognize it when: min or max over many ranges with updates.

  • 2286. Booking Concert Tickets in Groups
  • 1353. Maximum Number of Events That Can Be Attended (variant)
Counting with coordinate compression

Recognize it when: count of smaller / larger elements before or after i.

  • 315. Count of Smaller Numbers After Self
  • 327. Count of Range Sum
  • 493. Reverse Pairs
Range update with lazy propagation

Recognize it when: add or assign over ranges, then query.

  • 732. My Calendar III
  • 699. Falling Squares
  • 715. Range Module
04

Where it is used in real software

Time-series analytics

Dashboards answering min / max / sum over arbitrary time windows while new data points arrive use segment-tree-like aggregations.

Computational geometry

Rectangle union area and interval stabbing queries are solved with segment trees over sweep lines.

Game servers

Range queries over player rankings or map regions with frequent updates.

Databases

Some engines maintain aggregate trees to answer range aggregates without scanning every row.

05

Key terms

Node range
[start, end] of the array covered by a node.
Merge function
Associative operation combining children: sum, min, max, gcd.
Identity
Neutral value for the merge: 0 for sum, Infinity for min.
Lazy propagation
Store pending range updates at a node and push them to children only when needed.
4n array
An array of size 4n is always large enough for a recursive segment tree.
06

Query [l, r] recursively

  1. 1
    No overlap

    If the node's range is outside [l, r], return the identity (0 for sum).

  2. 2
    Full overlap

    If the node's range is inside [l, r], return the node's stored value.

  3. 3
    Partial overlap

    Query both children and merge their results.

  4. 4
    Point update

    Recurse into the child containing the index, update the leaf, then recompute each ancestor on the way back.

07

Sum query on [1, 4] for arr = [2, 1, 5, 3, 4, 2]

Root [0, 5] = 17; children [0, 2] = 8 and [3, 5] = 9

Step 1 / 9
Node rangeStored sumOverlap with [1, 4]Contributes
[0, 5]17partialask children
[0, 2]8partialask children
[0, 1]3partialask children
[0, 0]2none0
[1, 1]1full1
[2, 2]5full5
[3, 5]9partialask children
[3, 4]7full7
[5, 5]2none0

NOWNode range: [0, 5] | Stored sum: 17 | Overlap with [1, 4]: partial | Contributes: ask children

sum(1..4) = 1 + 5 + 7 = 13. Only O(log n) nodes contribute; the node [3, 4] answered two elements at once without visiting its leaves.

08

Implementation

class SegmentTree {  constructor(arr) {    this.n = arr.length;    this.tree = new Array(4 * this.n).fill(0);    this.#build(arr, 1, 0, this.n - 1);  }   #build(arr, node, start, end) {    if (start === end) {      this.tree[node] = arr[start];      return;    }    const mid = (start + end) >> 1;    this.#build(arr, 2 * node, start, mid);    this.#build(arr, 2 * node + 1, mid + 1, end);    this.tree[node] = this.tree[2 * node] + this.tree[2 * node + 1];  }   update(index, value, node = 1, start = 0, end = this.n - 1) {    if (start === end) {      this.tree[node] = value;      return;    }    const mid = (start + end) >> 1;    if (index <= mid) this.update(index, value, 2 * node, start, mid);    else this.update(index, value, 2 * node + 1, mid + 1, end);    this.tree[node] = this.tree[2 * node] + this.tree[2 * node + 1];  }   query(l, r, node = 1, start = 0, end = this.n - 1) {    if (r < start || end < l) return 0;              // no overlap    if (l <= start && end <= r) return this.tree[node]; // full overlap    const mid = (start + end) >> 1;    return this.query(l, r, 2 * node, start, mid) + this.query(l, r, 2 * node + 1, mid + 1, end);  }} const st = new SegmentTree([2, 1, 5, 3, 4, 2]);st.query(1, 4); // 13st.update(2, 10);st.query(1, 4); // 18
09

Complexity and performance

BuildO(n)

Each node computed once.

Point updateO(log n)

One root-to-leaf path.

Range queryO(log n)

At most about 4 nodes per level.

Range update (lazy)O(log n)

Defers work to later queries.

SpaceO(4n)

Array-based recursive layout.

10

Trade-offs

Segment tree vs prefix sum

Prefix sums are O(1) query but O(n) update. Use them for static arrays; use a segment tree when updates are frequent.

Segment tree vs Fenwick tree

Fenwick trees are shorter and faster for sums and prefix-based queries. Segment trees handle min / max, non-invertible merges, and lazy range updates more naturally.

Code length

Segment trees are long to write under interview pressure; practice the template until it is automatic.

11

Variants and related techniques

Iterative (bottom-up) segment tree

Size 2n array with leaves at n..2n - 1; shorter and faster for point updates.

Dynamic / sparse segment tree

Create nodes on demand for huge coordinate ranges (10^9).

Merge sort tree

Each node stores its sorted range; answers 'count values <= x in [l, r]'.

Persistent segment tree

Keeps old versions after updates; answers kth smallest in a range.

12

Common mistakes

  • Allocating 2n instead of 4n for the recursive version.

    Fix: Use 4n to avoid index overflow for non-power-of-two sizes.

  • Wrong identity for min queries.

    Fix: Return Infinity for no overlap, not 0.

  • Forgetting to push lazy values before recursing.

    Fix: Push pending updates to children before visiting them in partial overlaps.

13

Interview questions

Why is a range query O(log n)?

At each level of the tree, at most two nodes partially overlap the query range; fully covered nodes return immediately. With log n levels, only O(log n) nodes are visited.

What is lazy propagation?

Instead of updating every element in a range immediately, store the pending update at the highest fully covered nodes and push it to children only when a later operation needs to go deeper.

14

Practice problems

ProblemDifficultyWhat it trains
307. Range Sum Query - MutableMediumCore template.
2286. Booking Concert Tickets in GroupsHardMax and sum together.
315. Count of Smaller Numbers After SelfHardCoordinate compression.
732. My Calendar IIIHardRange add, max query.
699. Falling SquaresHardRange assign with lazy.