Fenwick Tree
A compact array-based tree that supports prefix-sum queries and point updates in O(log n) using the binary representation of indices.
Definition
A Fenwick tree (binary indexed tree) stores partial sums in an array tree[1..n] where tree[i] holds the sum of the lowbit(i) elements ending at i — lowbit(i) = i & -i is the value of the lowest set bit. With that layout a prefix sum sum(1..i) is obtained by repeatedly stripping the lowest set bit from i, and a point update a[i] += d is done by repeatedly adding the lowest set bit. Both loops run at most log₂ n + 1 times.
It solves the same problem as a Segment Tree restricted to invertible operations (sum, xor, counting) with one-third of the memory and a fraction of the code. Range sums come from prefix(r) - prefix(l - 1). With two Fenwick trees it also supports range add + range sum; with a tree over value-indices it counts "elements ≤ x seen so far" for inversion counting and order statistics.
Intuition
A mental model before the formal terms.
Picture the numbers 1 to 16 and imagine that each index i is responsible for a block of lowbit(i) cells ending at i: index 12 (1100₂) covers 4 cells (9–12), index 8 (1000₂) covers 8 cells (1–8), index 13 (1101₂) covers 1 cell. To get the sum of cells 1–13, read block 13 (cell 13), then block 12 (cells 9–12), then block 8 (cells 1–8): three reads, and 13 → 12 → 8 → 0 is exactly "remove the lowest set bit" each step.
Updating cell 5 (0101₂) must touch every block that contains it: 5, 6 (0110₂, cells 5–6), 8 (1000₂, cells 1–8), 16. Each is the previous one plus its lowest set bit.
How it works
- Use 1-based indexing.
treehas sizen + 1, initialized to zero. - update(i, delta):
while i <= n: tree[i] += delta; i += i & -i. - prefix(i):
s = 0; while i > 0: s += tree[i]; i -= i & -i; return s. - rangeSum(l, r) =
prefix(r) - prefix(l - 1). - build in O(n): copy
aintotree(1-based), then for eachi, letj = i + lowbit(i); ifj <= naddtree[i]totree[j]. - Find the smallest index with prefix ≥ k (order statistic): walk from the highest power of two downward, taking a step when the accumulated sum stays below
k.O(log n).
Why it works
Define tree[i] = sum(a[i - lowbit(i) + 1 .. i]). The ranges covered by i, i - lowbit(i), i - 2·lowbit(...)… are disjoint and tile [1, i] exactly, so summing them gives the prefix. Each subtraction clears one set bit, so at most log₂ n + 1 terms.
Cell i lies in the block of index j iff j - lowbit(j) < i ≤ j. The sequence i, i + lowbit(i), … enumerates exactly these j, and each step at least doubles the lowest set bit, so the update loop is also logarithmic.
Operations
| Operation | Description | Cost |
|---|---|---|
| update(i, delta) | Add delta to a[i] by climbing i += lowbit(i). | O(log n) |
| prefix(i) | Sum of a[1..i] by descending i -= lowbit(i). | O(log n) |
| rangeSum(l, r) | prefix(r) - prefix(l - 1). | O(log n) |
| build(a) | Linear-time construction by pushing each tree[i] into its parent. | O(n) |
| findByPrefix(k) | Smallest i with prefix(i) ≥ k using a binary-lifting walk. | O(log n) |
Recognition
How to tell a problem wants this.
- Prefix sums or range sums with point updates,
n, qup to10^5–10^6. - "Count how many previous elements are smaller" — inversion counts, "count of smaller numbers after self".
- Kth smallest in a multiset under insertions/deletions using a BIT over values.
- Any Segment Tree problem where the operation is invertible and memory or code size matters.
Interactive demo
Play, step, change the input. ← → and space work too.
1build: tree[i] += a[i]; j = i + (i & -i); if j <= n: tree[j] += tree[i]2update(i, delta): while i <= n: tree[i] += delta; i += i & -i3prefix(i): s = 0; while i > 0: s += tree[i]; i -= i & -i; return s4range(l, r) = prefix(r) - prefix(l-1)Pseudocode
1update(i, delta):2 while i <= n: tree[i] += delta; i += i & -i3prefix(i):4 s = 05 while i > 0: s += tree[i]; i -= i & -i6 return s7rangeSum(l, r): return prefix(r) - prefix(l - 1)Implementation
11 · 1-based tree array; lowbit(i) = i & -i2class FenwickTree:3 """tree[i] holds the sum of the lowbit(i) elements ending at index i."""4 5 def __init__(self, n_or_array: int | list[int]):6 if isinstance(n_or_array, int):7 self.n = n_or_array8 self.tree = [0] * (self.n + 1)9 else:10 # O(n) build: push each tree[i] into its parent.11 a = list(n_or_array)12 self.n = len(a)13 self.tree = [0] + a14 for i in range(1, self.n + 1):15 j = i + (i & -i)16 if j <= self.n:17 self.tree[j] += self.tree[i]18 192 · Point update: climb i += i & -i20 def update(self, i: int, delta: int) -> None:21 """a[i] += delta (1-based i)."""22 while i <= self.n:23 self.tree[i] += delta24 i += i & -i25 263 · Prefix sum: strip i -= i & -i27 def prefix(self, i: int) -> int:28 """Sum of a[1..i]."""29 s = 030 while i > 0:31 s += self.tree[i]32 i -= i & -i33 return s34 354 · Range sum from two prefixes36 def range_sum(self, l: int, r: int) -> int:37 """Sum of a[l..r], 1-based inclusive."""38 return self.prefix(r) - self.prefix(l - 1)39 405 · Smallest index with prefix >= k (binary lifting)41 def find_by_prefix(self, k: int) -> int:42 """Requires all values non-negative. Returns n + 1 if no such index."""43 pos = 044 step = 1 << self.n.bit_length()45 while step:46 nxt = pos + step47 if nxt <= self.n and self.tree[nxt] < k:48 pos = nxt49 k -= self.tree[nxt]50 step >>= 151 return pos + 1__init__acceptsint | list[int];isinstancenarrows it — a size allocates zeros, a list is copied behind a leading 0 and built in O(n) by pushing each slot into its parent.updateclimbsi += i & -i; Python's arbitrary-precision ints computei & -icorrectly for any positive i.prefixstrips the lowest set bit per iteration, summing the disjoint blocks tiling[1, i].range_sumsubtracts two prefixes (invertible operations only).find_by_prefixstarts the step at1 << n.bit_length()and halves it each round, walking right while the running sum stays belowk.
All loops are iterative — no recursion-limit concerns. Pure-Python loop overhead dominates; the same code with a C extension mindset would use numpy only for bulk builds, not per-op.
i & -iworks on Python's big ints because negative numbers behave as infinite two's complement.int.bit_length()replaces the manual "largest power of two ≤ n" loop used in other languages.- Type hints use the modern
int | list[int]union syntax (Python 3.10+).
- Calling
update(0, d)— index 0 makes the climb loop a no-op; shift application indices to 1-based. - Passing the new value rather than the delta; compute
delta = new - oldyourself. - Using
find_by_prefixwith negative values, breaking prefix monotonicity.
i & -i(lowbit) relies on two's complement: native in C++ and in JS/TS via 32-bit coercion; Python emulates infinite two's complement on big ints, so it also just works.- JS/TS bitwise coercion caps usable n below 2^31 and exact sums at 2^53; C++ uses
long long; Python has no limits on either. - Constructor overloading: real overloads in C++, a
number | number[]union narrowed bytypeofin TS,isinstancein Python. - Highest power of two ≤ n: a doubling loop in C++/JS/TS versus Python's
1 << n.bit_length()shifted down.
Complexity
| Operation | Average | Worst | Note |
|---|---|---|---|
| Access | O(log n) | O(log n) | a[i] = prefix(i) - prefix(i-1); keep the raw array for O(1). |
| Search | O(log n) | O(log n) | findByPrefix for monotone (non-negative) data. |
| Insert | — | — | Fixed size. |
| Delete | — | — | Update with -a[i]. |
| Update | O(log n) | O(log n) | |
| Build | O(n) | O(n) | |
| Prefix query | O(log n) | O(log n) | |
| Range query | O(log n) | O(log n) | |
| Point update | O(log n) | O(log n) | |
| Space | O(n) | Exactly n + 1 integers. 2D variant is O(n·m) space and O(log n · log m) per operation. | |
Advantages & disadvantages
- Ten lines of code and
n + 1integers of memory. - Excellent constant factors; cache-friendly array layout.
- Extends easily to 2D (
O(log² n)) and to range-update/range-query with two trees.
- Only invertible operations (sum, xor); no min/max range queries without tricks.
- No native range updates or lazy propagation — needs the two-tree transformation.
- The bit-manipulation layout is unintuitive; off-by-one errors with 0-based data are common.
Use cases
- Range Sum Query – Mutable and frequency counting under updates.
- Counting inversions and "smaller elements after self" with coordinate compression.
- Order statistics on a dynamic multiset (kth smallest via prefix walk).
- Arithmetic coding and cumulative frequency tables — Fenwick's original application.
- Prefix/range sums (or xor, counts) with point updates and tight memory or time limits.
- Inversion counting and "smaller to the right" after coordinate compression.
- Dynamic order statistics (kth smallest) via the prefix walk.
- Range min/max or other non-invertible aggregates — Segment Tree.
- Range updates with range queries of a non-sum kind — Segment Tree with lazy propagation.
- No updates — plain Prefix Sum.
Alternatives
Common mistakes
- Using index 0:
0 & -0 == 0makes the update loop never advance. Always shift to 1-based. - Passing the new value instead of the delta to
update. - Building with
ncalls toupdate(O(n log n)) when the linear build is available — fine for correctness, but avoid in tight limits. - Using
findByPrefixwith negative values, which breaks the monotonicity it relies on. - Overflow in sums — use 64-bit accumulators.
Interview patterns
- Range Sum Query – Mutable in ten lines.
- Count of smaller numbers after self: compress values, scan right-to-left,
prefix(v - 1)thenupdate(v, 1). - Number of longest increasing subsequences / LIS in
O(n log n)with a max-Fenwick over compressed values. - Two BITs for range add + range sum: derive
sum = (i+1)·B1(i) - B2(i). - 2D BIT for submatrix sums with updates.
- Recognizing the approach from an array and a targetIntermediate
- Deciding whether O(n²) can be improvedIntermediate
- Recognizing a sliding-window problemIntermediate
- Prefix sum or segment tree?Intermediate
- Minimum Size Subarray SumIntermediate
- Subarray Sum Equals KIntermediate