โ† Wiki Index / Computation & Algorithms / Fenwick Tree
๐Ÿ’ป Computation & Algorithms

Fenwick Tree

A Fenwick tree, or binary indexed tree, is an implicit zero-overhead array data structure that uses two's-complement least-significant set bits to compute dynamic prefix sums and point updates in O(log n) time.

Fenwick tree (also known as a Binary Indexed Tree, or BIT) is an implicit, space-optimal array data structure within computation and algorithms that maintains dynamic cumulative frequencies (prefix sums) of an array A[1..n] and executes both prefix queries and point updates in worst-case O(log n) time while using zero auxiliary memory beyond the n-element array itself. Invented in 1989 by Boris Ryabko and independently discovered and popularized in 1994 by Peter M. Fenwick in Software: Practice and Experience to accelerate dynamic symbol probability tables for arithmetic data compression, the Fenwick tree bridges the gap between a raw array (O(1) update, O(n) prefix sum) and a static prefix-sum array (O(n) update, O(1) prefix sum).

By indexing the array from 1 to n and decomposing every integer index i according to the least significant set bit in its binary representation, a Fenwick tree navigates an implicit binomial-like tree hierarchy using a single CPU two's-complement bitwise instruction (i & (โˆ’i)) per tree step. Within computational complexity theory and algorithm engineering, a Fenwick tree requires half to one-quarter the memory of a segment tree or balanced AVL tree and achieves high L1/L2 cache locality for dynamic rank queries, inversion counting, arithmetic coding, and Gillespie stochastic chemical simulation.

Binary Index Decomposition and Two's-Complement Bitwise Navigation

Responsibility Length lsb(i) = i & (โˆ’i)

Let A[1..n] be a 1-indexed array over an abelian group (G, +, โˆ’, 0). For any positive integer i โˆˆ {1, ..., n}, define lsb(i) (lowbit(i)) as the largest power of two 2k dividing iโ€”the value of the lowest set bit 1 in i. In two's-complement arithmetic, โˆ’i = (~i) + 1 inverts all bits above the lowest set bit k while preserving bit k = 1 and trailing zeros, so bitwise AND isolates 2k in one instruction:

lsb(i) = i & (โˆ’i) = 2ฮฝ2(i)

In the Fenwick array T[1..n], each slot T[i] stores the sum of a block of length lsb(i) ending at i:

T[i] = โˆ‘j = i โˆ’ lsb(i) + 1 .. i A[j]

Odd indices (i โ‰ก 1 mod 2) have lsb(i) = 1 (T[i] = A[i]), indices i โ‰ก 2 (mod 4) store 2-element sums, and powers of two i = 2k store full prefix sums A[1..2k].

Prefix Query (Stripping Lowest Bits) and Point Update (Propagating Carries)

Because i = 2k1 + ... + 2kr (r = popcount(i) โ‰ค โŒˆlog2(n + 1)โŒ‰), the prefix [1, i] partitions into r disjoint blocks. Computing Prefix-Sum(i) = โˆ‘j=1..i A[j] accumulates T[i] and strips lsb(i) until i = 0:

Prefix-Sum(i): s โ† 0; while i > 0: s โ† s + T[i]; i โ† i โˆ’ (i & (โˆ’i)); return s

Conversely, incrementing A[i] by ฮ” updates all containing ancestors j โ‰ฅ i by repeatedly adding lsb(i) until i > n:

Point-Update(i, ฮ”): while i โ‰ค n: T[i] โ† T[i] + ฮ”; i โ† i + (i & (โˆ’i))

Both operations run in at most โŒŠlog2 nโŒ‹ + 1 steps, and any range sum over [L, R] is Prefix-Sum(R) โˆ’ Prefix-Sum(L โˆ’ 1).

Linear-Time O(n) Construction, Binary Lifting, and Range-Update Extensions

In-Place O(n) Initialization vs. O(n log n) Insertion

Because each node T[i] has a unique parent p(i) = i + (i & (โˆ’i)) in the update tree, copying T[i] โ† A[i] and propagating each node's total to its immediate parent in a single forward sweep i = 1..n constructs the Fenwick tree in-place in O(n) time using n โˆ’ 1 additions:

for i = 1 to n: p โ† i + (i & (โˆ’i)); if p โ‰ค n, then T[p] โ† T[p] + T[i]

Binary Lifting and Dual Fenwick Trees for Range Updates

When all entries of A[1..n] are non-negative (A[i] โ‰ฅ 0), finding the smallest index i with Prefix-Sum(i) โ‰ฅ W via binary lifting steps k downward from โŒŠlog2 nโŒ‹ to 0 and advances idx โ† idx + 2k (subtracting T[idx + 2k] from W) whenever T[idx + 2k] < W, locating the target index in a single O(log n) pass.

To support adding ฮ” to a subarray A[L..R] while also querying Prefix-Sum(x), define the difference array D[i] = A[i] โˆ’ A[i โˆ’ 1]. Expanding the prefix sum algebraically yields:

โˆ‘i=1..x A[i] = (x + 1) โˆ‘j=1..x D[j] โˆ’ โˆ‘j=1..x (j ยท D[j])

Maintaining two Fenwick treesโ€”T1 storing D[j] and T2 storing (j โˆ’ 1)ยทD[j]โ€”evaluates both range additions and range sums in O(log n) time and 2n space.

Algorithmic OperationRaw Array A[1..n]Prefix-Sum Array P[1..n]Fenwick Tree T[1..n]Segment Tree (2nโ€“4n)
Construction Time & SpaceO(n) time, n wordsO(n) time, n wordsO(n) in-place, n wordsO(n) time, 2nโ€“4n words
Point Update A[i] += ฮ”O(1)O(n)O(log n) (โ‰ค log2 n writes)O(log n) (log2 n writes)
Prefix Sum [1..i] / Range Sum [L..R]O(n)O(1)O(log n) (popcount(i) reads)O(log n) (โ‰ค 2 log2 n reads)
Order-Statistic Lower Bound (โ‰ฅ W)O(n)O(log n) binary searchO(log n) via binary liftingO(log n) tree descent
Dynamic Range Minimum Query (RMQ)O(1) update, O(n) queryNot supportedO(log2 n) (requires 2 BITs)O(log n) native

Applications in Data Compression, Genomics, and Stochastic Simulation

Peter Fenwick designed the Binary Indexed Tree for adaptive arithmetic coding and the symbol-frequency stage downstream of the Burrowsโ€“Wheeler transform (which he integrated into the bzip2 compression ecosystem alongside Huffman coding): adaptive arithmetic coding updates the cumulative frequency interval [C(s), C(s + 1)) of each symbol s after every byte, which a Fenwick tree executes in O(log |ฮฃ|) time. In non-parametric statistics, sweeping an array A[1..n] while inserting each rank into a Fenwick tree counts array inversions (and computes Kendall's ฯ„ rank correlation) in O(n log n) time. In chemical kinetics, logarithmic direct Gillespie stochastic simulation algorithms (SSA) store reaction propensities aฮผ in a Fenwick tree and use binary lifting to sample the next firing biochemical reaction in O(log M) time.

Frequently Asked Questions

Why must a Fenwick tree use 1-based indexing instead of 0-based indexing?

In 1-based indexing, every valid index i โˆˆ {1, ..., n} has a non-zero least significant set bit lsb(i) = i & (โˆ’i) โ‰ฅ 1, so both i โˆ’ lsb(i) and i + lsb(i) terminate cleanly. If index 0 were passed into the standard bitwise loops, lsb(0) = 0, causing the update loop i โ† i + lsb(i) to stall at i = 0.

Why can a single Fenwick tree not answer arbitrary Range Minimum Queries in O(log n) time?

Range sum queries on [L, R] rely on the additive group inverse (โˆ’) so that the prefix [1, L โˆ’ 1] can be subtracted from [1, R]. The minimum operator min forms a semigroup without an inverse: knowing min(A[1..R]) and min(A[1..L โˆ’ 1]) does not determine min(A[L..R]) whenever the global minimum lies in [1, L โˆ’ 1], requiring a segment tree (O(log n)) instead.

References

  1. Ryabko, B. Y. (1989). "A fast on-line code." Soviet Mathematics Doklady, 39(3), 533โ€“537. https://mathscinet.ams.org/mathscinet-getitem?mr=1001696
  2. Fenwick, P. M. (1994). "A new data structure for cumulative frequency tables." Software: Practice and Experience, 24(3), 327โ€“336. https://doi.org/10.1002/spe.4380240306
  3. Fenwick, P. M. (1996). "Block sorting text compressionโ€”final report." The Computer Journal, 39(9), 731โ€“740. https://doi.org/10.1093/comjnl/39.9.731
  4. Mishra, P. (2013). "A new algorithm for updating and querying sub-arrays of multidimensional arrays." Journal of Cloud Computing, 2013, 1โ€“8. https://doi.org/10.48550/arXiv.1311.6093
  5. Pibiri, G. E., & Venturini, R. (2020). "Practical trade-offs for the prefix-sum problem." Software: Practice and Experience, 51(5), 921โ€“949. https://doi.org/10.1002/spe.2918
๐Ÿงฌ Support Open Science
Explore interactive science games on LowKey Games or browse scientific apparel & accessories in the CRV Science Shop.
๐Ÿ’ก Spot an inaccuracy or have primary literature to expand this article?
Submit a citation or revision note using your shared CRV Science / LowKey Games profile ID.
Suggest Revision