Segment Tree
Answer range queries and point updates in O(log n). Segment trees are the go-to structure for range sum, range min, and similar problems.
Interactive visualization
Use the controls to connect the idea to concrete operations before diving into the full write-up.
Family
Range queries
Static and dynamic range aggregates via indexed trees, segment trees, and precomputed tables.
Builds on
2 topics
Read these first if you want the surrounding context.
Unlocks
4 next topics
Use these follow-ups when you want to apply the current idea in a richer setting.
Learning paths
3
This topic appears in curated progressions so you can keep moving without guessing the next step.
Choose this over that
Use a segment tree only when you need its extra power
The heavier structure is worth it when the query or update model stops being prefix-friendly.
Fenwick Tree (Binary Indexed Tree)
Choose this when: You only need dynamic sums or prefix-style aggregates and want a lighter structure.
Choose something else when: Range updates, general associative merges, or tree flattening tricks are coming next.
Segment Tree
Choose this when: You need flexible merge operations, lazy propagation, or advanced variants like persistent or Li Chao trees.
Choose something else when: The array is static or sum-only logic is enough.
Sparse Table
Choose this when: Queries are static, idempotent, and should be as close to instant as possible.
Choose something else when: The structure needs to handle updates.
Problem
You have an array of elements. You need to:
- Query an aggregate (sum, min, max) over any subarray
- Update individual elements
A naive approach gives update and query, or update and query with prefix sums. A segment tree gives for both.
Intuition
Divide the array into segments recursively. Each node in the tree stores the aggregate for its segment. The root covers , its children cover and , and so on down to individual elements at the leaves. Any range can be decomposed into disjoint segments already stored in the tree.
Build
Construct bottom-up. Leaves hold the original array values. Each internal node merges its two children.
build(node, start, end, arr):
if start == end:
tree[node] ← arr[start]
return
mid ← (start + end) / 2
build(2*node, start, mid, arr)
build(2*node+1, mid+1, end, arr)
tree[node] ← tree[2*node] + tree[2*node+1]
time — each of the nodes is visited once.
Query
To query : at each node covering , either the segment is fully inside (return it), fully outside (return identity), or partially overlapping (recurse into both children and combine).
query(node, start, end, L, R):
if R < start or end < L: // no overlap
return 0
if L <= start and end <= R: // total overlap
return tree[node]
mid ← (start + end) / 2 // partial overlap
return query(2*node, start, mid, L, R)
+ query(2*node+1, mid+1, end, L, R)
At most nodes are visited — two per level of the tree.
Update
To update index : walk from the root to the leaf, then propagate the new aggregate back up.
update(node, start, end, i, val):
if start == end:
tree[node] ← val
return
mid ← (start + end) / 2
if i <= mid:
update(2*node, start, mid, i, val)
else:
update(2*node+1, mid+1, end, i, val)
tree[node] ← tree[2*node] + tree[2*node+1]
One root-to-leaf path → .
Lazy propagation
When you need range updates (add to every element in ), visiting every leaf is . Lazy propagation defers updates: mark a node as “pending” and only push the update down to children when they’re actually queried. This keeps both range update and range query at . The tradeoff is implementation complexity — you maintain a separate lazy[] array and flush pending updates before any node access.
Array representation
A segment tree on elements is stored in a flat array of size . Node has:
- Left child:
- Right child:
- Parent:
The root is at index 1 (index 0 is unused). This is the same trick as a binary heap but with 1-based indexing.
Common patterns
| Pattern | Merge operation | Identity |
|---|---|---|
| Range sum | ||
| Range min | ||
| Range max | ||
| Range GCD | ||
| Count in range | (with predicate at leaves) |
Any associative operation works. The merge function defines what your tree computes.
Complexity
| Operation | Time | Space |
|---|---|---|
| Build | ||
| Point query | — | |
| Range query | — | |
| Point update | — | |
| Range update (lazy) | extra |
Key takeaways
- Any associative operation works as the merge function — sum, min, max, GCD, bitwise OR. Define the merge and identity, and the tree handles the rest.
- for both query and update is the sweet spot between prefix sums ( query, update) and naive arrays ( query, update).
- Lazy propagation is essential for range updates — without it, updating a range of elements is . With it, both range update and query stay .
- Flat array of size with 1-based indexing — node has children and . No pointers, no overhead, cache-friendly.
- Segment trees dominate when you need both updates and queries — if the array is static, prefer a sparse table or prefix sums.
Practice problems
| Problem | Difficulty | Key idea |
|---|---|---|
| Range Sum Query - Mutable | 🟡 Medium | Direct segment tree application for sum queries with point updates |
| My Calendar I | 🟡 Medium | Segment tree or balanced BST to detect overlapping intervals |
| Count of Smaller Numbers After Self | 🔴 Hard | Segment tree on value space, processing array right to left |
| The Skyline Problem | 🔴 Hard | Sweep line with segment tree or priority queue for active heights |
| Count of Range Sum | 🔴 Hard | Segment tree on prefix sums to count valid ranges |
Relation to other topics
Fenwick tree (BIT): simpler to implement, less memory, but only supports prefix queries natively. You can do range queries with two prefix queries, but operations like range min don’t work. If all you need is range sum with point updates, a Fenwick tree is lighter.
Sparse table: range min/max queries after preprocessing, but the array must be static — no updates allowed.
Sqrt decomposition: per query and update. Much simpler to implement. Good enough when and you want fast coding time over optimal asymptotic complexity.
Build on these first
These topics supply the mental model or underlying structure that this page assumes.
Tree Fundamentals
Understand roots, parents, children, depth, height, and traversal orders. A tree is a graph with enough structure to make many problems much simpler.
Prefix Sum
Precompute cumulative totals so any range sum becomes one subtraction. Prefix sums are the first serious range-query idea everyone should know.
What this enables
Once the current idea feels natural, these are the most useful next jumps.
Euler Tour Technique
Flatten a rooted tree into an array so subtree problems become range problems. This is the bridge between trees and range-query structures.
Heavy-Light Decomposition
Break tree paths into O(log n) heavy-chain segments so path queries can ride on top of a segment tree instead of walking edge by edge.
Li Chao Tree
Maintain dynamic line insertion and min/max queries by storing line candidates in a segment tree over x-values.
Persistent Segment Tree
Keep every version of a segment tree by path-copying only the changed nodes.
Related directions
These topics live nearby conceptually, even if they are not direct prerequisites.
Binary Search Tree (BST)
A sorted tree structure enabling O(log n) search, insert, and delete. Foundation for balanced trees, sets, and maps.
Binary Lifting
Jump upward in a rooted tree by powers of two to answer k-th ancestor and many LCA-style queries quickly.
Euler Tour Technique
Flatten a rooted tree into an array so subtree problems become range problems. This is the bridge between trees and range-query structures.
Heavy-Light Decomposition
Break tree paths into O(log n) heavy-chain segments so path queries can ride on top of a segment tree instead of walking edge by edge.
More from Range queries
Stay in the same family when you want parallel variations of the same mental model.
Prefix Sum
Precompute cumulative totals so any range sum becomes one subtraction. Prefix sums are the first serious range-query idea everyone should know.
Difference Array
Apply many range updates in O(1) each, then rebuild the final values with one prefix pass. Difference arrays are the update-side twin of prefix sums.
Fenwick Tree (Binary Indexed Tree)
Maintain prefix sums with O(log n) updates and queries using one tiny bit trick. Fenwick trees are the lightest dynamic range-query structure worth knowing.
Li Chao Tree
Maintain dynamic line insertion and min/max queries by storing line candidates in a segment tree over x-values.
Paths that include this topic
Follow one of these sequences if you want a guided next step instead of open-ended browsing.
Range-query toolkit
Start with static prefix tricks, then move into offline, persistent, dynamic, and precomputed range-query structures.
Rooted tree queries
Flatten subtrees, jump through ancestors, and break tree paths into array segments instead of climbing naively.
Tree path queries
Build the full ladder from ancestor queries to heavy-light decomposition and historical segment trees.
From the blog
Pair the atlas with recent writing from the rest of the site when you want a broader engineering perspective alongside the topic graph.