Segment Tree / Fenwick Tree
A compact array structure for prefix sum queries and point updates in O(log n). Each index stores the sum of a range determined by its lowest set bit. Simpler to implement than a segment tree for prefix sums.
A plain prefix-sum array answers "sum of elements from index 1 to i" in , but updating a single element requires time to recompute all subsequent prefix values. A Fenwick tree, also called a Binary Indexed Tree, or BIT, brings both operations down to while using only extra space and remarkably little code. It is the right tool whenever you need prefix sums on a mutable array and you don't require range-minimum or range-maximum (for those, reach for a segment tree instead).
Every positive integer can be decomposed by its binary representation. The expression i & (-i) isolates the lowest set bit of i. For example:
6 & -6 = 2 (binary 010)4 & -4 = 4 (binary 100)7 & -7 = 1 (binary 001)A Fenwick tree uses this value to decide how much of the prefix each index "owns." Index i in the BIT array stores the sum of exactly i & (-i) consecutive elements ending at position i. Index 4 (binary 100, lowest bit = 4) is responsible for elements [1, 4]. Index 6 (binary 110, lowest bit = 2) covers [5, 6]. Index 7 (binary 111, lowest bit = 1) covers only [7, 7].
This encoding is what makes both operations fast: a prefix query decomposes into a chain of non-overlapping ranges by repeatedly stripping the lowest set bit, and an update propagates through the indices that "own" ranges containing the changed position by repeatedly adding the lowest set bit.
To find the sum of elements from 1 to i, start at i and collect tree[i], then jump to i - (i & -i), collect again, and repeat until i reaches zero. Each step removes one bit, so the loop runs at most times.
class BIT:
def __init__(self, n):
self.n = n
self.tree = [0] * (n + 1) # 1-indexed
def query(self, i):
s = 0
while i > 0:
s += self.tree[i]
i -= i & (-i)
return sTo add delta to element i, start at i, add delta to tree[i], then jump to i + (i & -i) and repeat until i exceeds n. This visits every index whose responsible range includes position i.
def update(self, i, delta):
while i <= self.n:
self.tree[i] += delta
i += i & (-i)A range sum [l, r] is simply the difference of two prefix queries: query(r) - query(l - 1). This is the same identity used for static prefix arrays, now available in with updates.
def range_query(self, l, r):
return self.query(r) - self.query(l - 1)Consider the array [2, 1, 5, 3, 4] (1-indexed). Initialize a BIT of size 5 and call update(i, arr[i]) for each position.
After all updates, tree[4] holds the sum of [1, 4] = 11, because index 4 (binary 100) owns four elements. To answer query(5):
Now update index 3 by adding 2 (new value 7). Call update(3, 2):
Only two nodes updated. Subsequent prefix queries will automatically reflect the change.
LeetCode 307. Range Sum Query - Mutable is the canonical Fenwick problem: build the BIT from the input, expose update(i, val - arr[i]) to overwrite a position, and answer sumRange(l, r) with query(r+1) - query(l) (after shifting to 1-indexed).
LeetCode 315. Count of Smaller Numbers After Self walks the array right to left, querying the BIT for the count of values already inserted that are strictly smaller than the current element, then inserting that element. With coordinate compression, this gives an solution to a problem that is by brute force.
LeetCode 493. Reverse Pairs and the closely related problem of counting inversions, pairs where but arr[i] > arr[j], fall out of the same pattern. For inversions: process left to right, and for each element x, query the BIT for "how many elements already inserted are greater than x." With coordinate compression mapping values to , this becomes query(n) - query(x) after inserting x via update(x, 1). The total across all elements is the inversion count, computed in .
LeetCode 327. Count of Range Sum wants the number of prefix-sum pairs whose difference lies in . Compute all prefix sums, coordinate-compress them, then for each prefix sum query the BIT for the count of prior in before inserting .
LeetCode 1395. Count Number of Teams generalizes inversion counting to triples: for each middle element, count how many smaller elements are to its left and how many larger are to its right (and vice-versa). Two BIT sweeps deliver the answer in .
For sub-rectangle sum queries on a 2D grid with point updates, a 2D BIT extends naturally. The tree becomes a 2D array, and both update and query perform nested loops: the outer loop over rows uses the same i += i & (-i) / i -= i & (-i) logic, and the inner loop does the same for columns. Time per operation is for an grid.
class BIT2D:
def __init__(self, m, n):
self.m, self.n = m, n
self.tree = [[0] * (n + 1) for _ in range(m + 1)]
def update(self, r, c, delta):
i = r
while i <= self.m:
j = c
while j <= self.n:
self.tree[i][j] += delta
j += j & (-j)
i += i & (-i)
def query(self, r, c):
s = 0
i = r
while i > 0:
j = c
while j > 0:
s += self.tree[i][j]
j -= j & (-j)
i -= i & (-i)
return sFor prefix-sum queries with point updates, a Fenwick tree is strictly simpler: it requires less code, has smaller constant factors, and uses exactly words of memory. A segment tree, by contrast, needs space and more bookkeeping. The trade-off is generalization: segment trees support range-minimum, range-maximum, arbitrary associative operations, and lazy-propagation range updates. If you only need sum with point updates, reach for the BIT. If you need anything else, use the segment tree.
Both update and query run in time. Building the BIT by calling update times costs ; a smarter construction exists but the simpler approach is almost always fast enough. Space is .
You're probably looking at a Fenwick tree when:
Common templates:
Practice Problems (10)