Skip to content
advancedPhase 7 · Advanced Topics

Fenwick Tree

Master Binary Indexed Trees for prefix sum queries and updates.

1h
4 problems
Topic Progress0%

Fenwick Tree Fundamentals

What is a Fenwick Tree?

A Fenwick Tree (also called Binary Indexed Tree or BIT) is a data structure that efficiently supports:

  • Point updates: Add a value to an element
  • Prefix queries: Query sum from index 0 to i

Both operations in O(log n) time with O(n) space.

Key Insight: Binary Representation

The magic of Fenwick Tree is using the binary representation of indices:

Index:    1    2    3    4    5    6    7    8
Binary:  001  010  011  100  101  110  111 1000

BIT[1] covers: [1]
BIT[2] covers: [1,2]
BIT[3] covers: [3]
BIT[4] covers: [1,2,3,4]
BIT[5] covers: [5]
BIT[6] covers: [5,6]
BIT[7] covers: [7]
BIT[8] covers: [1,2,3,4,5,6,7,8]

Implementation

public class FenwickTree {
    private int[] tree;
    private int n;
    
    public FenwickTree(int size) {
        n = size;
        tree = new int[n + 1]; // 1-indexed
    }
    
    public FenwickTree(int[] nums) {
        n = nums.length;
        tree = new int[n + 1];
        for (int i = 0; i < n; i++) {
            update(i, nums[i]);
        }
    }
    
    // Add val to index i (0-indexed)
    public void update(int i, int val) {
        i++; // Convert to 1-indexed
        while (i <= n) {
            tree[i] += val;
            i += i & (-i); // Add lowest set bit
        }
    }
    
    // Query prefix sum from 0 to i (0-indexed)
    public int query(int i) {
        i++; // Convert to 1-indexed
        int sum = 0;
        while (i > 0) {
            sum += tree[i];
            i -= i & (-i); // Remove lowest set bit
        }
        return sum;
    }
    
    // Query range sum from left to right (0-indexed)
    public int rangeQuery(int left, int right) {
        return query(right) - query(left - 1);
    }
}

The XOR Trick

i & (-i) gives the lowest set bit:

  • If i = 6 (110), then -i = ...010, so i & (-i) = 2 (010)
  • This tells us how far the current node reaches

Time & Space Complexity

  • Build (from array): O(n log n) or O(n) with optimized build
  • Update: O(log n)
  • Query: O(log n)
  • Space: O(n)

Advanced Fenwick Tree Applications

2D Fenwick Tree

For 2D range queries and updates:

public class FenwickTree2D {
    private int[][] tree;
    private int rows, cols;
    
    public FenwickTree2D(int m, int n) {
        rows = m;
        cols = n;
        tree = new int[m + 1][n + 1];
    }
    
    public void update(int row, int col, int val) {
        for (int i = row + 1; i <= rows; i += i & (-i)) {
            for (int j = col + 1; j <= cols; j += j & (-j)) {
                tree[i][j] += val;
            }
        }
    }
    
    public int query(int row, int col) {
        int sum = 0;
        for (int i = row + 1; i > 0; i -= i & (-i)) {
            for (int j = col + 1; j > 0; j -= j & (-j)) {
                sum += tree[i][j];
            }
        }
        return sum;
    }
    
    public int rangeQuery(int r1, int c1, int r2, int c2) {
        return query(r2, c2) - query(r1 - 1, c2) - query(r2, c1 - 1) + query(r1 - 1, c1 - 1);
    }
}

Counting Inversions with Fenwick Tree

public int countInversions(int[] nums) {
    // Coordinate compression
    int[] sorted = nums.clone();
    Arrays.sort(sorted);
    Map<Integer, Integer> map = new HashMap<>();
    int rank = 1;
    for (int num : sorted) {
        map.putIfAbsent(num, rank++);
    }
    
    FenwickTree ft = new FenwickTree(rank);
    int inversions = 0;
    
    // Process from right to left
    for (int i = nums.length - 1; i >= 0; i--) {
        int r = map.get(nums[i]);
        inversions += ft.query(r - 1); // Count smaller elements to the right
        ft.update(r, 1);
    }
    
    return inversions;
}

Dynamic Frequency Counting

// Count numbers in range [left, right] that have been added so far
class FrequencyCounter {
    private FenwickTree ft;
    private int offset;
    
    public FrequencyCounter(int maxValue) {
        offset = maxValue; // Handle negative numbers
        ft = new FenwickTree(2 * maxValue + 1);
    }
    
    public void add(int num) {
        ft.update(num + offset, 1);
    }
    
    public void remove(int num) {
        ft.update(num + offset, -1);
    }
    
    public int countInRange(int left, int right) {
        return ft.rangeQuery(left + offset, right + offset);
    }
}

Practice Problems

0/1solved
Count of Smaller Numbers After Self
Fenwick Tree / BIT

Given an integer array nums, return an integer array counts where counts[i] is the number of smaller elements to the right of nums[i].

Example:

Input: nums = [5,2,6,1]

Output: [2,1,1,0]

To the right of 5: [2,6,1] → 2 smaller (2,1). To the right of 2: [6,1] → 1 smaller (1). To the right of 6: [1] → 1 smaller (1). To the right of 1: [] → 0 smaller.

Solution
```java
public List<Integer> countSmaller(int[] nums) {
    int max = Arrays.stream(nums).max().getAsInt();
    int min = Arrays.stream(nums).min().getAsInt();
    int offset = -min;
    
    FenwickTree ft = new FenwickTree(max - min + 2);
    List<Integer> result = new ArrayList<>();
    
    for (int i = nums.length - 1; i >= 0; i--) {
        int count = ft.query(nums[i] + offset - 1);
        result.add(0, count);
        ft.update(nums[i] + offset, 1);
    }
    
    return result;
}
```

Edge Cases:

  • All elements same
  • Already sorted array
  • Reverse sorted array
  • Contains negative numbers

Quiz

1. What does `i & (-i)` compute in a Fenwick Tree?

Question 1 options

2. Which operation is NOT efficiently supported by a standard Fenwick Tree?

Question 2 options

3. What is the primary purpose of Fenwick Tree (Binary Indexed Tree)?

Question 3 options

4. What is a common mistake when implementing Fenwick Tree (Binary Indexed Tree)?

Question 4 options

Flashcards

Question

What is the time complexity for update and query in a Fenwick Tree?

Answer

Both update and query are O(log n). The Fenwick Tree uses the binary representation of indices to traverse the tree in logarithmic steps.

Question

Why is a Fenwick Tree preferred over a Segment Tree for prefix sum problems?

Answer

Fenwick Tree is simpler to implement, uses less space (O(n) vs O(4n)), and has smaller constants. It's ideal when you only need prefix sums and point updates.

Question

What is Fenwick Tree (Binary Indexed Tree)?

Answer

Fenwick Tree (Binary Indexed Tree) is a key concept in software engineering.

Question

When to use Fenwick Tree (Binary Indexed Tree)?

Answer

Use Fenwick Tree (Binary Indexed Tree) when building production systems that require reliability, scalability, and maintainability.

Question

Fenwick Tree (Binary Indexed Tree) best practices

Answer

Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.

Revision Notes

Key Takeaways

  • 1.Fenwick Tree provides O(log n) point updates and prefix queries
  • 2.Uses binary representation of indices for efficient traversal
  • 3.Simpler and more space-efficient than Segment Tree
  • 4.Ideal for prefix sum and frequency counting problems
  • 5.Can be extended to 2D for matrix range queries

Interview Tips

  • Fenwick Tree is great for counting problems involving order statistics
  • Use coordinate compression when dealing with large value ranges
  • For inversion count: process right-to-left, query sum of smaller elements
  • Remember: i & (-i) gives the lowest set bit - this is the key trick
  • Practice: Count of Smaller Numbers After Self, Range Sum Query - Mutable

Cheat Sheet

Fenwick Tree Cheat Sheet

Core Operations

// Add val at index i (0-indexed)
void update(int i, int val) {
    i++;
    while (i <= n) {
        tree[i] += val;
        i += i & (-i);
    }
}

// Prefix sum [0..i] (0-indexed)
int query(int i) {
    i++;
    int sum = 0;
    while (i > 0) {
        sum += tree[i];
        i -= i & (-i);
    }
    return sum;
}

// Range sum [l..r]
int rangeQuery(int l, int r) {
    return query(r) - query(l - 1);
}

Key Insight

i & (-i) = lowest set bit

  • 6 (110) & -6 (..010) = 2 (010)
  • 8 (1000) & -8 (..1000) = 8 (1000)

Applications

  1. Prefix Sum: O(log n) query
  2. Count Inversions: Process right-to-left, query count of smaller
  3. 2D Range Queries: Use 2D BIT
  4. Frequency Counting: Count numbers in ranges

vs Segment Tree

Feature Fenwick Tree Segment Tree
Implementation Simpler Complex
Space O(n) O(4n)
Range Min/Max No Yes
Range Updates Limited Full (lazy)