Skip to content
Home DSA Fenwick Tree (Binary Indexed Tree) — Efficient Prefix Sums

Fenwick Tree (Binary Indexed Tree) — Efficient Prefix Sums

Where developers are forged. · Structured learning · Free forever.
📍 Part of: Trees → Topic 9 of 15
Learn how a Fenwick tree (BIT) supports prefix sum queries and point updates in O(log n) time using bit manipulation to navigate a clever tree structure.
🔥 Advanced — solid DSA foundation required
In this tutorial, you'll learn
Learn how a Fenwick tree (BIT) supports prefix sum queries and point updates in O(log n) time using bit manipulation to navigate a clever tree structure.
  • Fenwick Tree answers prefix sum queries in O(log n) using the lowest set bit of index for range boundaries.
  • The i & -i trick isolates the lowest set bit, enabling O(log n) navigation up or down the implicit tree.
  • BITs are simpler and faster than segment trees for sum queries but cannot easily support non-invertible operations like range max.
✦ Plain-English analogy ✦ Real code with output ✦ Interview questions
Quick Answer

Imagine a library with 16 shelves of books. Instead of counting every book from shelf 1 to shelf 10 each time someone asks, you pre-assign certain shelves to be 'summary shelves' that already know the total for a range. When a book is added, only a handful of those summary shelves update — not all 16. A Fenwick Tree does exactly that for numbers: it lets you update a value and ask 'what's the total from position 1 to position k?' in a handful of steps instead of scanning everything.

Competitive programmers love Fenwick Trees because they solve a brutally common problem — range prefix-sum queries with point updates — in O(log n) time AND O(n) space, with constants so small the code fits in about 10 lines. You'll find them inside database engines for order-book aggregations, in game servers tracking cumulative scores, and in every serious competitive programming solution that involves frequency arrays or inversions. If you've ever hit a TLE on a naive cumulative-sum approach, a Fenwick Tree is likely the fix.

The core problem is this: you have an array of numbers that changes over time, and you need to repeatedly answer 'what is the sum of elements from index 1 to index k?' A flat prefix-sum array answers queries in O(1) but updates in O(n). A Fenwick Tree gives you O(log n) for both, with a constant factor that is almost embarrassingly small — often 3–5x faster in wall-clock time than a segment tree for the same problem.

By the end of this article you'll understand exactly why the bit-manipulation trick i += i & (-i) works, how to extend the tree for range updates and point queries, how to do a binary search on the tree itself, and the exact production bugs that bite engineers the first time they ship this structure in real code.

What is a Fenwick Tree? — Plain English

A Fenwick Tree (also called Binary Indexed Tree or BIT) is a data structure that answers the question 'what is the sum of elements from index 1 to i?' in O(log n) time, while also allowing you to update any element in O(log n) time. A naive array handles point updates in O(1) but prefix sums in O(n). A prefix sum array handles queries in O(1) but updates in O(n). A Fenwick tree strikes the middle — O(log n) for both. The trick is that each node in the BIT stores the sum of a specific range of elements, and the range size is determined by the lowest set bit of the node's index. For example, index 6 (binary 110) has lowest bit 2, so it stores the sum of 2 elements: arr[5]+arr[6].

How Fenwick Tree Works — Step by Step

Building and querying a BIT on arr=[1,3,5,7,9,11] (1-indexed, n=6):

Update(i, delta): add delta to BIT[i], then move to the next responsible node by adding the lowest set bit of i. 1. update(3, 5): BIT[3] += 5, then 3+(3&-3)=3+1=4 → BIT[4] += 5, then 4+4=8 > n, stop.

Query(i): sum from 1 to i by traversing upward removing the lowest set bit. 1. query(6): sum += BIT[6]; 6-(6&-6)=6-2=4 → sum += BIT[4]; 4-4=0 → stop. Sum = BIT[6]+BIT[4]. 2. BIT[6] covers arr[5]+arr[6]=9+11=20; BIT[4] covers arr[1]+arr[2]+arr[3]+arr[4]=1+3+5+7=16. Total=36.

Range query(l,r) = query(r) - query(l-1).

Worked Example — Tracing BIT Construction

Build BIT for arr=[1,3,5,7,9,11] (1-indexed).

Initialize BIT=[0,0,0,0,0,0,0] (index 0 unused).

update(1,1): BIT[1]+=1 → BIT[1]=1. 1+(1&-1)=1+1=2 → BIT[2]+=1 → BIT[2]=1. 2+2=4 → BIT[4]+=1=1. 4+4=8>6, stop. update(2,3): BIT[2]+=3=4. 2+2=4 → BIT[4]+=3=4. 8>6 stop. update(3,5): BIT[3]+=5=5. 3+1=4 → BIT[4]+=5=9. 8>6 stop. update(4,7): BIT[4]+=7=16. 4+4=8>6 stop. update(5,9): BIT[5]+=9=9. 5+1=6 → BIT[6]+=9=9. 6+2=8>6 stop. update(6,11): BIT[6]+=11=20. 6+2=8>6 stop.

Final BIT=[0,1,4,5,16,9,20]. query(6): BIT[6]=20; 6-2=4; BIT[4]=16; 4-4=0 stop. Sum=36. Correct (1+3+5+7+9+11=36).

Implementation

A BIT is implemented as a 1-indexed array. The update operation adds a delta to BIT[i] and propagates to parent nodes by adding the lowest set bit (i += i & -i). The query operation accumulates sums by stripping the lowest set bit (i -= i & -i) until i reaches 0. Construction can be done in O(n log n) via n updates, or O(n) by a smarter initialization. Point update with range query is the most common variant; range update with point query requires a difference BIT.

fenwick_tree.py · PYTHON
1234567891011121314151617181920212223242526272829303132333435
class FenwickTree:
    def __init__(self, n):
        self.n = n
        self.bit = [0] * (n + 1)  # 1-indexed

    def update(self, i, delta):
        """Add delta to position i (1-indexed)."""
        while i <= self.n:
            self.bit[i] += delta
            i += i & (-i)  # move to next responsible node

    def query(self, i):
        """Prefix sum from 1 to i (1-indexed)."""
        total = 0
        while i > 0:
            total += self.bit[i]
            i -= i & (-i)  # remove lowest set bit
        return total

    def range_query(self, l, r):
        """Sum from l to r (both 1-indexed)."""
        return self.query(r) - self.query(l - 1)

    def build(self, arr):
        """Build from 0-indexed array in O(n log n)."""
        for i, val in enumerate(arr):
            self.update(i + 1, val)

# Example
ft = FenwickTree(6)
ft.build([1, 3, 5, 7, 9, 11])
print(ft.query(6))        # 36 (sum of all)
print(ft.range_query(2,4)) # 15 (3+5+7)
ft.update(3, 2)            # arr[3] becomes 7
print(ft.range_query(2,4)) # 17 (3+7+7)
▶ Output
36
15
17
ConceptUse CaseExample
Fenwick Tree — Binary Indexed TreeCore usageSee code above

🎯 Key Takeaways

  • Fenwick Tree answers prefix sum queries in O(log n) using the lowest set bit of index for range boundaries.
  • The i & -i trick isolates the lowest set bit, enabling O(log n) navigation up or down the implicit tree.
  • BITs are simpler and faster than segment trees for sum queries but cannot easily support non-invertible operations like range max.

⚠ Common Mistakes to Avoid

    Memorising syntax before understanding the concept
    Skipping practice and only reading theory

Interview Questions on This Topic

  • QWhat is the time complexity of BIT update and query?
  • QHow does i & -i isolate the lowest set bit?
  • QWhen would you choose BIT over segment tree?

Frequently Asked Questions

What does 'i & -i' compute and why is it useful?

In two's complement arithmetic, -i flips all bits of i and adds 1. ANDing i with -i isolates only the lowest set bit of i. For example, i=6 (binary 110): -6 = ...11111010, i&-i = 010 = 2. This value tells us the range size that BIT[i] is responsible for, and adding or subtracting it navigates the tree.

When should I use a Fenwick tree vs a segment tree?

Fenwick trees are simpler to code (5-10 lines) and faster in practice due to cache efficiency. Use a BIT when you need prefix sums with point updates. Use a segment tree when you need range queries other than sum (e.g., range max/min), or when you need lazy propagation for range updates.

Can a Fenwick tree handle range updates?

Yes, with a technique called the 'difference BIT'. Store differences instead of values. A range update [l,r] by delta becomes two point updates: update(l, +delta) and update(r+1, -delta). Then prefix_sum(i) gives the actual value at position i. For range-update + range-query, you need two BITs.

🔥
Naren Founder & Author

Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.

← PreviousSegment TreeNext →Trie Data Structure
Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged