The Fenwick Tree (Binary Indexed Tree)

•16 min read•

The Fenwick tree, frequently referred to as a binary indexed tree[1] (BIT), is a specialized data structure[2] designed to efficiently update elements and calculate prefix sums[3] in an array of numbers.[30][31] By representing cumulative frequencies as a conceptual tree mapped directly onto a flat array, the structure bypasses the need for complex pointer-based node allocations. It relies heavily on the properties of binary numbers[4] and bitwise operations[5] to traverse the conceptual tree. Specifically, it isolates the least significant bit[6] of an index to determine the exact range of elements for which that index is responsible.

In computational terms, the Fenwick tree provides a highly optimized solution to the dynamic range sum query[7] problem.[32] When maintaining a sequence of numbers where values are frequently updated and sums over arbitrary intervals are frequently requested, naive approaches suffer from linear time complexity[8] in either the update or the query operation. The Fenwick tree reduces the time complexity of both operations to logarithmic time, while requiring only linear space. The constant factors hidden by the asymptotic Big O notation[9] are exceptionally small, making the structure extremely fast in practice.

Originally developed in the context of arithmetic data compression[10] to maintain dynamic cumulative frequency tables, the Fenwick tree has expanded far beyond its initial domain. It is now a standard algorithm in competitive programming, database query optimization, statistical sampling, and bioinformatics.[33] Its minimal memory footprint and short implementation code make it a preferred choice over larger, more generalized structures when the required operations are associative[11] and possess a mathematical inverse[12].

Mathematical Formalization and The Problem

The core problem addressed by the Fenwick tree involves an array[13] of numbers, $A$, of size $n$. An algorithm must perform two specific operations on this array:

  1. update(i, delta): Add a value delta to the element at index $i$.
  2. query(i): Compute the sum of all elements from index 1 to index $i$.

A standard array allows the update operation to complete in $O(1)$ time by directly modifying $A[i]$. However, the query operation requires iterating through all elements from 1 to $i$, resulting in $O(n)$ time complexity. Conversely, if the algorithm maintains a prefix sum array where each index $i$ stores the sum of elements from 1 to $i$, the query operation completes in $O(1)$ time. In this scenario, the update operation degrades to $O(n)$ time, because changing a single element requires recalculating all subsequent prefix sums.

The Fenwick tree bridges this gap. It structures the data such that both the update and query operations complete in $O(\log n)$ time. Furthermore, any arbitrary range sum from index $L$ to index $R$ can be computed by subtracting two prefix sums: query(R) - query(L - 1). This makes the Fenwick tree an optimal choice for applications requiring continuous, interleaved updates and queries on a dataset. The logarithmic time complexity represents a theoretical lower bound for dynamic prefix sum problems in the cell-probe model, proving that the Fenwick tree is asymptotically optimal for this specific class of operations.

The mathematical correctness of the Fenwick tree relies on the fact that any integer $i$ can be uniquely represented as a sum of distinct powers of two, which corresponds directly to its binary representation. For example, the number 13 is represented in binary as 1101, which equals $8 + 4 + 1$. The Fenwick tree uses this property to partition the prefix sum of 13 into exactly three non-overlapping blocks. The first block covers the single element at index 13. The second block covers the four elements from index 9 to 12. The third block covers the eight elements from index 1 to 8. The lengths of these blocks correspond exactly to the powers of two in the binary representation of the index. Because the maximum index $n$ has at most $\lfloor \log_2 n \rfloor + 1$ bits, the number of blocks accessed during any query is strictly bounded by $O(\log n)$.

Mechanism and Implementation

The standard Fenwick tree operates on a 1-based array. The size of the array is $n$. For any index $i$, the tree stores the sum of elements in the original array from index $i - \text{LSB}(i) + 1$ to $i$. The LSB (Least Significant Bit) of $i$ represents the largest power of two that evenly divides $i$.

In modern computing, the LSB is extracted using the bitwise AND operation between the number and its Two's complement[14] negation: i & (-i). Signed integers are typically represented using Two's complement. To find the Two's complement of a number, the system inverts all the bits (changing 1s to 0s and 0s to 1s) and then adds 1 to the result. When the bits are inverted, the lowest set bit becomes a 0, and all the trailing 0s become 1s. When 1 is added to the inverted value, the trailing 1s carry over and flip back to 0s, and the 0 (which was originally the lowest 1) flips back to a 1. All bits to the left of this position remain inverted. Therefore, the only bit that is identical in both the original number and its negation is the least significant set bit. When the bitwise AND operation is applied, all the higher bits cancel out to 0, leaving only the LSB.

For example, consider the index 12. In binary, 12 is represented as 1100. The Two's complement of 12 is 0100 (which is decimal 4). The bitwise AND of 1100 and 0100 is 0100 (decimal 4). Thus, the LSB of 12 is 4. This means the element at index 12 in the Fenwick tree is responsible for 4 elements in the original array. Specifically, it stores the sum of elements from index 9 to 12.

To execute a prefix sum query for index 12, the algorithm accesses the value at index 12 (which covers 9 to 12). It then subtracts the LSB from 12, resulting in 8. It accesses the value at index 8. The binary representation of 8 is 1000. The LSB of 8 is 8. Thus, index 8 covers the 8 elements from index 1 to 8. The algorithm adds the value at index 8 to the running total. Subtracting the LSB from 8 results in 0. The loop terminates. The total sum is the sum of the values at index 12 and index 8, which perfectly covers the range from 1 to 12.

To execute an update at index 9, the algorithm must add the delta to every position in the Fenwick tree that includes index 9 in its range of responsibility. The algorithm starts at index 9 (binary 1001). It adds the delta to the value at index 9. It then adds the LSB of 9 (which is 1) to the index, resulting in 10 (binary 1010). It adds the delta to the value at index 10. It adds the LSB of 10 (which is 2) to the index, resulting in 12 (binary 1100). It adds the delta to the value at index 12. It adds the LSB of 12 (which is 4) to the index, resulting in 16 (binary 10000). This process continues until the index exceeds the size of the array.

def update(tree, i, delta):
    while i < len(tree):
        tree[i] += delta
        i += i & (-i)

def query(tree, i):
    total = 0
    while i > 0:
        total += tree[i]
        i -= i & (-i)
    return total

A naive construction of the Fenwick tree involves initializing an empty array of zeros and calling the update function $n$ times. Because each update takes $O(\log n)$ time, the total time complexity for this construction is $O(n \log n)$. A more efficient algorithm constructs the tree in strictly linear $O(n)$ time.

def build_tree(arr):
    n = len(arr)
    tree = [0] * (n + 1)
    for i in range(1, n + 1):
        tree[i] += arr[i - 1]
        parent = i + (i & (-i))
        if parent <= n:
            tree[parent] += tree[i]
    return tree

The algorithm begins by copying the original array values into the Fenwick tree array. It then iterates through the array from index 1 to $n$. For each index $i$, the algorithm identifies the immediate parent of $i$ in the conceptual tree by adding the LSB to $i$. If the parent index is less than or equal to $n$, the algorithm adds the current value at index $i$ to the value at the parent index. By propagating the sums upward one level at a time, every node accumulates the correct total for its entire range of responsibility in a single pass. When the algorithm processes index 1, it adds its value to its parent at index 2. When it processes index 2, the node already contains the combined sum of 1 and 2, and the algorithm adds this combined sum to its parent at index 4. This cascading effect ensures that higher nodes receive complete block sums in constant time per node.

Discovery and History

The data structure was invented by Peter M. Fenwick and published in 1994 in the journal Software: Practice and Experience[15]. At the time, Fenwick was a researcher at the University of Auckland[16]. His research focused on arithmetic data compression.

In arithmetic coding, a message is compressed by representing it as a fractional number within a specific interval between 0 and 1. The algorithm divides the interval based on the probability distribution of each symbol in the alphabet. To determine the correct sub-interval for a given symbol, the algorithm requires the cumulative frequency of all preceding symbols. Because the compression is adaptive, the frequencies of the symbols change continuously as the file is processed. This requires the algorithm to perform one update and one prefix sum query for every single character in the input stream. A file with one million characters requires one million updates and one million queries.

Prior to Fenwick's publication, compression algorithms managed these frequencies using a move-to-front heuristic, a heap structure, or splay trees. These methods required extensive data reorganization and pointer manipulation. Fenwick proposed a flat array structure that required zero data movement, relying entirely on bitwise arithmetic to traverse the conceptual tree.

Independent of Fenwick, the Russian mathematician Boris Ryabko[17] developed a mathematically equivalent structure. Ryabko published his findings in 1989 and expanded upon them in a 1992 paper titled "A fast on-line adaptive code" in the IEEE Transactions on Information Theory. While Ryabko established the theoretical bounds and the tree structure for the same arithmetic coding problem, Fenwick's 1994 paper introduced the highly optimized bitwise array implementation that is universally used today. In 1996, Fenwick published a follow-up paper detailing an improved frequency-to-symbol algorithm, which allowed the tree to be searched in logarithmic time to find the specific symbol corresponding to a given cumulative frequency.

Advanced Variants and Extensions

0-Based Indexing

While the standard Fenwick tree uses 1-based indexing, it can be adapted for 0-based arrays. In a 1-based tree, the LSB of 0 is 0, which causes an infinite loop in the update function because adding 0 to the index does not advance it. To implement a 0-based Fenwick tree, the bitwise operations must be modified. Instead of i & (-i), the algorithm uses (i & (i + 1)) - 1 to find the parent for queries, and i | (i + 1) to find the next node for updates. This alternative bitwise logic achieves the exact same logarithmic traversal without requiring the array to be padded with a dummy element at index 0.

Multidimensional Fenwick Trees

The logic of the Fenwick tree extends naturally to multiple dimensions. For a two-dimensional grid of size $N \times M$, a 2D Fenwick tree can maintain the sum of elements in any rectangular subgrid. The update and query operations use nested loops, each advancing by the LSB.

def update_2d(tree, x, y, delta):
    i = x
    while i < len(tree):
        j = y
        while j < len(tree[i]):
            tree[i][j] += delta
            j += j & (-j)
        i += i & (-i)

The time complexity for both operations becomes $O(\log N \times \log M)$. For a 3D Fenwick tree representing a spatial volume, the array is indexed by $x$, $y$, and $z$ coordinates. An update at $(x, y, z)$ requires three nested loops. This is particularly useful in computational physics and graphics for maintaining dynamic voxel grids or calculating cumulative particle densities in three-dimensional space.

Range Update and Point Query

While the standard Fenwick tree supports point updates and range queries, it can be adapted to support range updates and point queries using a difference array. Instead of storing the original values, the tree stores the differences between adjacent elements. To add a value $V$ to a range from $L$ to $R$, the algorithm adds $V$ to index $L$ and subtracts $V$ from index $R + 1$. A point query for index $x$ is then computed by taking the prefix sum of the difference array up to index $x$.[34]

Range Update and Range Query

By combining the difference array concept with algebraic manipulation, the Fenwick tree can support both range updates and range queries. This requires maintaining two separate Fenwick trees. When a value $V$ is added to the range from $L$ to $R$, the prefix sum up to an index $x$ depends on how many times each difference value is included in the sum. The mathematical expansion of the prefix sum of a difference array $D$ up to index $x$ simplifies to $(x + 1) \sum_{i=1}^x D[i] - \sum_{i=1}^x (D[i] \times i)$. The first tree maintains the standard difference array $D[i]$. The second tree maintains the weighted difference array $D[i] \times i$. The prefix sum is calculated by querying both trees and applying the formula.

Order Statistic Tree and Binary Lifting

A Fenwick tree can function as an order statistic tree[18] to find the $k$-th smallest element in a dynamic multiset. By storing the frequencies of elements in the tree, the algorithm can use a technique called binary lifting. The algorithm maintains a running index and a running sum, examining each bit of the index from most significant to least significant. It determines the highest power of two less than or equal to $n$. If adding this power of two to the current index keeps the cumulative frequency strictly less than $k$, the algorithm permanently adds the power of two to the index and updates the running sum. It then halves the power of two and repeats the process. This examines each bit of the target index exactly once, constructing the correct index bit by bit. This finds the target element in $O(\log n)$ time without requiring a full binary search over the prefix sums, which would otherwise take $O(\log^2 n)$ time.

Real-World Applications

The Fenwick tree is a foundational component in modern data compression algorithms. Implementations of the Burrows-Wheeler transform[19] and Prediction by Partial Matching (PPM) algorithms use Fenwick trees to maintain dynamic cumulative frequency tables, but bzip2 uses Huffman coding, not arithmetic coding, and does not use Fenwick trees for dynamic cumulative frequency tables. The structure allows these compressors to adapt to changing symbol probabilities in real time without incurring significant computational overhead.

In the domain of competitive programming, the Fenwick tree is a standard tool. It is heavily featured in textbooks such as Competitive Programming[20] by Halim and online resources like CP-Algorithms[21] and SPOJ[22]. Programmers prefer it over other data structures due to its short implementation length and low constant factors, which are advantageous in strictly timed environments.

In bioinformatics and computational genetics, the Fenwick tree accelerates complex simulations. The msprime[23] library, a widely used tool for coalescent simulation of genetic ancestry, uses a Fenwick tree to select ancestral segments during recombination events in logarithmic time. Similarly, the phylo2vec[24] software, developed in collaboration with the eScience Institute, uses Fenwick trees to optimize operations on phylogenetic trees, reducing the time complexity of vector transformations from quadratic to linearithmic time.

In statistical computing, the randomForestSRC[25] package available on the Comprehensive R Archive Network (CRAN) uses a Fenwick tree to compute concordance-based performance metrics. Specifically, it computes the Uno inverse-probability-of-censoring weighting in $O(n \log n)$ time, replacing a naive $O(n^2)$ pairwise computation.

The data structure is also taught in university computer science curricula. The Fenwick tree does not appear in Introduction to Algorithms[27] by Cormen, Leiserson, Rivest, and Stein, nor is it standard in Princeton University's[26] algorithms course. Implementations are readily available in package repositories, such as the fenwick library on the Python Package Index (PyPI[28]).

Significance, Hardware Efficiency, and Tradeoffs

The primary advantage of the Fenwick tree is its extreme memory efficiency. It requires exactly $n$ elements of storage, identical to the original array. It uses no pointers, objects, or structural metadata. This contiguous memory layout results in excellent cache locality, making the operations significantly faster in practice than pointer-based trees. A standard binary search tree requires allocating a node object for every element, scattering nodes across the heap memory. Traversing such a tree requires following memory pointers, and each pointer dereference can cause a cache miss, forcing the CPU to fetch data from main memory.

Conversely, a Fenwick tree stores all data in a single contiguous array. When the CPU fetches an element, it pulls an entire cache line into the L1 cache. Subsequent accesses in the bitwise loop often hit the same cache line, resulting in memory access times of just a few clock cycles. Modern CPU architectures rely heavily on branch prediction and memory prefetching. The Fenwick tree's predictable, tight loops and sequential memory access patterns align perfectly with these hardware optimizations, minimizing cache misses and pipeline stalls. The constant factors hidden by the asymptotic notation consist only of basic arithmetic and bitwise operations.

However, the Fenwick tree has strict mathematical limitations compared to a segment tree[29]. A segment tree is a full binary tree where each node represents an interval of the array. Because the segment tree stores the exact result for each specific interval, it can answer a query for any arbitrary range by combining a small number of disjoint intervals. This allows a segment tree to answer arbitrary range queries for any associative operation, including operations that lack an inverse, such as finding the maximum or minimum value in a range.

The Fenwick tree natively computes only prefix queries.[35] To compute a range query from $L$ to $R$, the algorithm must compute the prefix query for $R$ and subtract the prefix query for $L - 1$. This subtraction requires the operation to have a mathematical inverse. Therefore, a standard Fenwick tree cannot efficiently answer range maximum or range minimum queries. Additionally, a segment tree can be easily modified to support complex lazy propagation for arbitrary range updates, whereas the Fenwick tree requires specific algebraic manipulations that only work for simple operations like addition.

This fundamental structural difference explains why segment trees require $4n$ memory space to store the full tree structure, while Fenwick trees require only $n$ space. When the problem involves invertible operations, the Fenwick tree is universally preferred for its simplicity, speed, and minimal memory footprint.

Sources (35)
  1. Wikipedia: binary indexed tree
  2. Wikipedia: data structure
  3. Wikipedia: prefix sums
  4. Wikipedia: binary numbers
  5. Wikipedia: bitwise operations
  6. Wikipedia: least significant bit
  7. Wikipedia: dynamic range sum query
  8. Wikipedia: time complexity
  9. Wikipedia: Big O notation
  10. Wikipedia: arithmetic data compression
  11. Wikipedia: associative
  12. Wikipedia: inverse
  13. Wikipedia: array
  14. Wikipedia: Two's complement
  15. Software: Practice and Experience
  16. Wikipedia: University of Auckland
  17. IEEE
  18. Wikipedia: order statistic tree
  19. Wikipedia: Burrows-Wheeler transform
  20. Competitive Programming
  21. CP-Algorithms
  22. SPOJ
  23. msprime
  24. escience.washington.edu: phylo2vec
  25. randomForestSRC
  26. algs4.cs.princeton.edu: Princeton University
  27. mitpress.mit.edu: Introduction to Algorithms
  28. PyPI
  29. Wikipedia: segment tree
  30. Adam Jones, Advanced Java Data Structures: Techniques and Applications for Efficient Programming (Walzone Press, 2025)
  31. Arvind Choudhary, DSA with Python Programming (Aravind Choudhary, 2026)
  32. Dr. K. Rajendra Prasad, Mr. Shambhu Sharan Srivastava, Mrs. P. Revathy, Advanced Data Structures and Algorithms - Beyond the Basics (RK Publication, 2024)
  33. Sri. Ramakrishna Pradhana, Dr. S. Prasanna Kumaar, Bhakti P.Thakre, Nurjabova Dilafruz Shukurullaevna, Data Structures and Algorithms (BR Publications, 2026)
  34. Arvind Choudhary, DSA with C++ & Python and Java Programming (Aravind Choudhary, 2026)
  35. Arvind Choudhary, DSA with C & C++ and Python Programming (Aravind Choudhary, 2026)