↓Skip to main content
  1. Algorithms/

Segment Tree and Fenwick Tree

·3 mins· ·
Algorithm Segment-Tree Binary-Indexed-Tree Design
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Introduction
#

Prefix Sum answers range sums in O(1), but changing one value means rebuilding the prefix array in O(n). When the array changes, use a structure that supports partial updates:

StructureUpdateQueryGood for
Prefix sumO(n)O(1)No modifications
Fenwick treeO(log n)O(log n)Point updates + prefix sums (subtract for a range)
Segment treeO(log n)O(log n)Any mergeable range operation (sum, max, min), extensible to range updates

Template 1: Fenwick tree (binary indexed tree)
#

tree[i] covers a range of length i & -i (the lowest 1 bit of i). Indices start at 1:

class Fenwick:
    def __init__(self, n):
        self.tree = [0] * (n + 1)

    def add(self, i, delta):             # nums[i] += delta, i starts at 1
        while i < len(self.tree):
            self.tree[i] += delta
            i += i & -i                  # up: the next cell whose range covers i

    def prefix(self, i):                 # sum of nums[1..i]
        s = 0
        while i > 0:
            s += self.tree[i]
            i -= i & -i                  # left: drop the range this cell covers
        return s

A range sum is prefix(r) - prefix(l - 1). When the problem says “set to val”, compute the difference val - nums[i] first and add it, which means keeping a copy of the array.

Template 2: Segment tree
#

Node node covers [start, end], with children 2 * node + 1 and 2 * node + 2, in an array of size 4n:

def build(node, start, end):
    if start == end:
        tree[node] = nums[start]
        return
    mid = (start + end) // 2
    build(2 * node + 1, start, mid)
    build(2 * node + 2, mid + 1, end)
    tree[node] = tree[2 * node + 1] + tree[2 * node + 2]

def query(node, start, end, l, r):
    if r < start or end < l:             # no overlap
        return 0
    if l <= start and end <= r:          # fully covered
        return tree[node]
    mid = (start + end) // 2
    return query(2 * node + 1, start, mid, l, r) + query(2 * node + 2, mid + 1, end, l, r)

An update walks down to the leaf like the build, then recomputes every parent on the way back.

  • Mutable range sums (LC 307): either works; Fenwick is shorter, and a segment tree extends more easily.

Key Parameters
#

  • Fenwick indices start at 1, and i & -i is the lowest 1 bit of i.
  • Segment tree ranges are inclusive [start, end]; mid belongs to the left half.

Complexity
#

Build in O(n) (adding one by one into a Fenwick tree is O(n log n)), each update and query O(log n), space O(n).

Common Mistakes
#

These are mistakes I actually made while practicing:

  • Both children computed as the same node: the right child was written 2 * node + 1, same as the left (LC 307).
  • No return after recursing: both halves were queried but their sum was never returned, giving None (LC 307).

Related LeetCode#

  • LC 307 Range Sum Query - Mutable

Related

LeetCode 307: Range Sum Query - Mutable
·3 mins
LeetCode Medium Segment-Tree Binary-Indexed-Tree Design Array
LeetCode 307 note: point updates with range sums make prefix sums O(n) per update; a segment tree or Fenwick tree makes both operations O(log n)
Queue and Design Problems
·3 mins
Algorithm Queue Design Iterator Lazy-Deletion
Circular queues, zigzag iterators, FIFO matching with cancellation, and the data structure combinations that design problems keep using
Array Scanning
·7 mins
Algorithm Array Simulation Enumeration
Adjacent comparisons and walking monotonic runs (uphill, downhill, hills and valleys), keeping prefix / suffix maximums and sums in one pass, enumerating pairs in small ranges, and breaking ties with tuple keys
Bit Manipulation
·5 mins
Algorithm Bit-Manipulation
Common bit operations, AND only removes bits while OR only adds them, finding adjacent ones with n & (n » 1), and all-ones numbers 2^k - 1
Bucket Sort and the Pigeonhole Principle
·2 mins
Algorithm Bucket-Sort Pigeonhole-Principle Sorting
Split the value range into n - 1 buckets; the largest gap can never fall inside one bucket, so keeping each bucket’s minimum and maximum finds the maximum adjacent difference in linear time
Hash Table
·8 mins
Algorithm Hash-Table Counting Array
Counting and frequency of frequencies, using the array itself as a hash table (sign marking), counting several keys at once (rows, columns, diagonals), incremental counts from a fixed left end, and grouping by a normalized key