AlgoMaster Logo

Fenwick Tree (Binary Indexed Tree)

Medium Priority16 min readUpdated June 4, 2026
Listen to this chapter
Unlock Audio

You have an array of n integers and need to support two operations:

  1. Update a single element.
  2. Compute the prefix sum from index 1 to i.

A plain array gives O(1) updates but O(n) prefix sums. A prefix sum array gives O(1) prefix sums but O(n) updates, because every update invalidates the precomputed sums after that index.

The Fenwick Tree (also called Binary Indexed Tree, or BIT) gives O(log n) for both. The entire structure rests on a single operation: i & (-i), which isolates the lowest set bit of i.

A segment tree (covered in the next chapter) can do everything a BIT can do and more, but a BIT uses about half the code and has lower constant factors when the operation is invertible (sum, XOR).

The Core Idea

The Problem

Let us frame the trade-off clearly.

With a plain array, updating an element is O(1), but computing a prefix sum requires iterating from index 0 to i, which is O(n).

With a prefix sum array, querying a range sum is O(1), but updating a single element forces you to rebuild part of the prefix array, which is O(n).

What we want is a structure where both operations cost O(log n). The Fenwick Tree delivers exactly that.

The Key Insight: Lowest Set Bit

Every positive integer has a binary representation, and every binary representation has a lowest set bit, the rightmost 1. For example:

Index (decimal)BinaryLowest Set Biti & (-i)
1000111
2001022
3001111
4010044
5010111
6011022
7011111
8100088

The expression i & (-i) isolates this lowest set bit. In two's complement, -i flips all bits of i and adds 1, so i & (-i) zeroes out everything except the rightmost 1. Every update and query in a BIT is built on top of this one operation.

Here is how it works: the lowest set bit of index i determines the responsibility range of that position in the BIT. Position i stores the sum of i & (-i) elements ending at index i.

  • Index 1 (lowest set bit = 1): responsible for 1 element, just a[1]
  • Index 2 (lowest set bit = 2): responsible for 2 elements, a[1] + a[2]
  • Index 3 (lowest set bit = 1): responsible for 1 element, just a[3]
  • Index 4 (lowest set bit = 4): responsible for 4 elements, a[1] + a[2] + a[3] + a[4]
  • Index 6 (lowest set bit = 2): responsible for 2 elements, a[5] + a[6]
  • Index 8 (lowest set bit = 8): responsible for 8 elements, a[1] + ... + a[8]

Responsibility Ranges

The following diagram shows how each BIT position covers a range of the original array (for an array of size 8).

Nodes with larger lowest-set-bit values sit higher in the hierarchy and cover wider ranges. Nodes with a lowest set bit of 1 (odd indices) are always leaves, covering just a single element.

How It Works: Core Operations

Internal Representation

A Fenwick Tree is stored as a 1-indexed array of size n + 1. Index 0 is unused (or set to 0). 1-indexing is required for the bit trick to terminate: 0 & (-0) = 0, so calling update(0, ...) would loop forever, and query(0) needs to stop at 0.

There is no actual tree object in memory

Unlike a binary tree with explicit pointers or even a heap-style array layout, a Fenwick Tree is just a flat array. The "tree" structure exists only in the parent-child relationship encoded by i & (-i). The parent of index i is i + (i & (-i)), and the elements that contribute to the prefix sum at i are visited by repeatedly subtracting the lowest set bit. The hierarchy in the diagram above is implicit, not stored.

0-based variants exist (using i | (i + 1) and (i & (i + 1)) - 1), but 1-based is the standard convention and the code below uses it throughout.

Point Update: update(i, delta)

To add delta to position i, you walk upward through the tree. Starting at index i, you add delta to BIT[i], then move to the next position by adding the lowest set bit: i += i & (-i). You repeat until i exceeds n.

Why does this work? Every position j that is responsible for a range containing index i must be updated. The "add lowest set bit" operation visits exactly those positions, climbing from narrow ranges to wider ones.

Starting at index 3 (binary 011), the lowest set bit is 1, so we jump to 3 + 1 = 4. At index 4 (binary 100), the lowest set bit is 4, so we jump to 4 + 4 = 8. At index 8, if this is the last valid index, we stop. Only 3 positions were touched for an array of size 8, which is log2(8) = 3.

Prefix Query: query(i)

To compute the prefix sum from index 1 to i, you walk downward. Starting at index i, you accumulate BIT[i] into a running sum, then move to the next position by subtracting the lowest set bit: i -= i & (-i). You repeat until i reaches 0.

The intuition for the two directions

Every position i is contained in exactly the responsibility ranges of the nodes visited by repeatedly adding the lowest set bit (those are the BIT positions whose range covers index i, so an update at i must touch all of them). And the prefix [1..i] decomposes into exactly the disjoint responsibility ranges of the nodes visited by repeatedly subtracting the lowest set bit (stripping the lowest 1-bit hops back to the previous range boundary).

Updates walk up; queries walk down. Both visit O(log n) positions because each step either sets or clears a single bit, and there are at most log n bits.

To compute the prefix sum up to index 7, we visit BIT[7] (covers a[7]), then BIT[6] (covers a[5..6]), then BIT[4] (covers a[1..4]). Adding those three stored values gives us a[1] + a[2] + ... + a[7]. Again, only 3 lookups for an 8-element array.

Range Query: rangeQuery(l, r)

A range sum from index l to r is simply query(r) - query(l - 1). This follows the same logic as prefix sum arrays: the sum of elements in [l, r] equals the prefix sum up to r minus the prefix sum up to l - 1.

Building the BIT: O(n) Approach

You could build a BIT by calling update for each element, but that gives O(n log n). There is a cleaner O(n) approach: copy the original array into the BIT array, then for each index i from 1 to n, propagate BIT[i] to its parent j = i + (i & (-i)) (if j <= n). A single forward pass suffices because parents always have a higher index than children, so by the time we reach i in the loop, BIT[i] already contains the full sum of its responsibility range.

Example Walkthrough

Let us work through a concrete example with the array a = [1, 3, 5, 7, 2, 4, 6, 8] (8 elements, 1-indexed).

Step 1: Building the BIT

We start by copying the array into BIT positions 1 through 8, then propagating each position to its parent.

Let us verify a few values:

  • BIT[1] = a[1] = 1. Correct (covers only a[1]).
  • BIT[2] = a[1] + a[2] = 1 + 3 = 4. Correct (covers a[1..2]).
  • BIT[4] = a[1] + a[2] + a[3] + a[4] = 1 + 3 + 5 + 7 = 16. Correct (covers a[1..4]).
  • BIT[6] = a[5] + a[6] = 2 + 4 = 6. Correct (covers a[5..6]).
  • BIT[8] = a[1] + ... + a[8] = 36. Correct (covers a[1..8]).

Step 2: Querying Prefix Sum Up to Index 6

We want query(6), which should return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] = 1 + 3 + 5 + 7 + 2 + 4 = 22.

Two lookups to sum six elements, instead of six additions.

Step 3: Updating Index 3 by +2

We want to add 2 to a[3], making it 7 instead of 5. This means update(3, 2).

Step 4: Querying Range Sum [3, 6] After the Update

Range sum [3, 6] = query(6) - query(2).

After the update, a = [1, 3, 7, 7, 2, 4, 6, 8], so the expected answer is 7 + 7 + 2 + 4 = 20.

Implementation

Here is a complete Fenwick Tree implementation. It builds the tree from an array in O(n), supports point updates with update, prefix sums with query, and range sums with rangeQuery, all using the lowest-set-bit idiom on 1-indexed positions.

Code Explanation

The implementation is intentionally simple in structure. Let us walk through the key design decisions.

The constructor performs an O(n) build

Instead of calling update n times (which would be O(n log n)), we copy the array into BIT positions 1 through n, then make a single forward pass. For each index i, we push its value to its parent i + (i & (-i)). Since each element has exactly one parent, this is a linear operation. This is a subtle but important optimization. In an interview, it shows you understand the parent-child relationships in the tree, not just the query/update mechanics.

Update walks upward using i += i & (-i)

Each iteration moves to the next position whose responsibility range includes index i. Because each step at least doubles i (removing the lowest set bit and adding a higher power of 2), the loop runs at most log n times.

Query walks downward using i -= i & (-i)

Each iteration strips away the lowest set bit, moving to the next non-overlapping range that contributes to the prefix sum. Since each step reduces i by at least 1 (and each bit can only be stripped once), the loop runs at most log n times.

Range query is a simple difference

This is the same trick as prefix sum arrays: sum(l, r) = prefix(r) - prefix(l-1).

Complexity Analysis

Time Complexity

Both update and query run in O(log n) time. Here is why:

  • In update, each step computes i += i & (-i). The lowest set bit is removed and a higher bit is set, so i strictly increases. Since i is bounded by n, the loop can execute at most floor(log2(n)) times.
  • In query, each step computes i -= i & (-i). The lowest set bit is removed, so the number of set bits in i decreases by 1 each iteration. A number with at most floor(log2(n)) bits means at most that many iterations.

Building the BIT takes O(n) with the propagation approach, or O(n log n) with repeated updates.

Space Complexity

O(n) for the BIT array. Unlike a segment tree (which needs 2n or 4n space), a BIT uses exactly n + 1 elements. This lower space usage also means better cache performance in practice.

Comparison Table

OperationPrefix Sum ArrayFenwick TreeSegment Tree
BuildO(n)O(n)O(n)
Point UpdateO(n)O(log n)O(log n)
Prefix QueryO(1)O(log n)O(log n)
Range QueryO(1)O(log n)O(log n)
Range UpdateO(n)O(log n)*O(log n)
SpaceO(n)O(n)O(2n) to O(4n)
Code ComplexityVery simpleSimpleModerate

*Range update with a BIT requires the difference array technique (covered in the next section).

For problems that only need prefix sums with point updates, a BIT is the better tool than a segment tree. Reach for a segment tree when you need range min/max or lazy propagation.

Variations and Extensions

Range Update + Point Query

Sometimes you need the opposite pattern: update an entire range [l, r] by adding a value, then query the value at a single point. A BIT handles this using the difference array concept.

Instead of storing actual values, store differences. To add delta to range [l, r]:

  • Call update(l, delta)
  • Call update(r + 1, -delta)

To query the value at position i, call query(i). The prefix sum of the difference array gives you the actual value at that position.

This works because adding delta at position l and subtracting it at position r + 1 means the prefix sum from l to r increases by delta, and everything after r cancels out.

2D Fenwick Tree

For problems involving a 2D grid where you need to update individual cells and query rectangular sub-sums, extend the BIT to two dimensions. Each operation becomes a nested loop:

Both operations are O(log n * log m) for an n x m grid. To query any arbitrary rectangle (x1, y1) to (x2, y2), use inclusion-exclusion:

rectSum = query(x2,y2) - query(x1-1,y2) - query(x2,y1-1) + query(x1-1,y1-1)

BIT for Order Statistics

A BIT can answer "how many elements less than x have been inserted so far?" in O(log n). This is the basis for inversion counting and online rank queries.

The idea: treat the BIT as a frequency array. When you insert a value v, call update(v, 1). To find how many values less than or equal to v have been inserted, call query(v). With coordinate compression (mapping large values to a compact range), this handles arbitrary integer ranges.

Variants Summary

VariantUpdateQueryUse Case
Standard BITPoint O(log n)Prefix sum O(log n)Dynamic prefix sums
Range update BITRange O(log n)Point O(log n)Difference array problems
2D BITPoint O(log n * log m)Rectangle sum O(log n * log m)Matrix sub-sums
Order statistics BITInsert O(log n)Rank O(log n)Inversion counting, ranking

Comparison with Related Structures

Understanding when to choose a Fenwick Tree versus its alternatives is just as important as knowing how it works.

CriterionPrefix SumFenwick TreeSegment Tree
Query timeO(1)O(log n)O(log n)
Update timeO(n)O(log n)O(log n)
SpaceO(n)O(n)O(2n) to O(4n)
Supports min/maxNoNoYes
Range updates + Range queriesNoLimitedYes (with lazy propagation)
Code complexity~5 lines~15 lines~40 lines
Constant factorLowestLowModerate

When to choose a Fenwick Tree:

  • The problem involves prefix sums (or can be reduced to prefix sums) with point updates.
  • You want minimal code in a contest setting.
  • Memory is tight, a BIT uses about half the space of a segment tree.
  • The operation is invertible (addition, XOR). BITs rely on computing range results as a difference of two prefix results, which requires the operation to have an inverse.

When NOT to use a Fenwick Tree:

  • You need range minimum or range maximum queries. These operations are not invertible, so you cannot compute min(l, r) as min(1, r) - min(1, l-1). Use a segment tree instead.
  • You need both range updates and range queries simultaneously. While a BIT can handle range-update-point-query or point-update-range-query, doing both requires two BITs and the approach is fragile. A segment tree with lazy propagation is cleaner.
  • The problem requires more complex operations like "find the first index where prefix sum exceeds k." A segment tree supports binary search on its structure natively.

Common Patterns and Applications

Pattern 1: Inversion Counting

Problem: Given an array, count the number of pairs (i, j) where i < j and a[i] > a[j].

Approach: Process the array from right to left. For each element a[i], query the BIT for "how many elements smaller than a[i] have we already seen?" (these are elements to the right of i that are smaller, meaning a[i] forms an inversion with each of them). Then insert a[i] into the BIT.

This runs in O(n log n), matching merge sort but with a completely different approach.

Pattern 2: Frequency Counting with Coordinate Compression

Many problems give you large value ranges (up to 10^9) but small array sizes (up to 10^5). You cannot create a BIT of size 10^9, but you can compress the values to the range [1, n] while preserving their relative order. This is called coordinate compression, and it pairs perfectly with BITs.

The steps are:

  1. Collect all values that appear.
  2. Sort them and assign ranks 1, 2, 3, ...
  3. Use the rank as the BIT index.

This pattern appears in problems like "count of smaller numbers after self" and "count of range sum."

Pattern 3: Dynamic Cumulative Sums

Any time you have a running stream of values and need to answer prefix/range sum queries interspersed with updates, a BIT is the natural choice. This comes up in:

  • Real-time leaderboard scores
  • Running frequency histograms
  • Dynamic cumulative distribution functions
  • Online algorithms that process elements one at a time

Summary

  • A Fenwick Tree (Binary Indexed Tree) provides O(log n) point updates and O(log n) prefix sum queries, filling the gap between O(1)-query/O(n)-update prefix sum arrays and the heavier segment tree.
  • The entire structure is driven by one operation: i & (-i), which isolates the lowest set bit and determines responsibility ranges. Update walks up (add lowest set bit), query walks down (subtract lowest set bit).
  • BITs work for invertible operations (addition, XOR) but not for min/max. When you need min/max queries or lazy propagation, use a segment tree instead.
  • The O(n) build technique (propagating each node to its parent in a single forward pass) is a detail worth knowing for interviews.
  • Common applications include dynamic prefix sums, inversion counting, coordinate-compressed frequency queries, and 2D sub-rectangle sums.
PropertyValue
Time (update)O(log n)
Time (query)O(log n)
SpaceO(n)
PrerequisitesPrefix sums, basic bit manipulation
Best forDynamic prefix sums, inversion counting, frequency queries
Avoid whenRange min/max, non-invertible operations, range update + range query

Quiz

Fenwick Tree (Binary Indexed Tree) Quiz

10 quizzes