We need dynamic prefix sums and range sum queries over a stream of financial ledger transactions where numbers are constantly updated.
A standard array has O(1) update but O(N) range sum. A prefix sum array has O(1) range sum but O(N) update. Segment trees solve both in O(log N) but require 4N memory and complex pointer/tree logic. Peter Fenwick’s Binary Indexed Tree (BIT) solves both in O(log N) with zero tree nodes and only 1N memory using the bit trick i & (-i). How does this lowbit navigation work?
The Fenwick Tree (invented by Peter Fenwick in 1994) is one of the most compact data structures ever devised. It gives you the full power of a dynamic segment tree in just one flat array of size N with 10 lines of code.
1. The Secret: Powers of 2 Range Decomposition
Any positive integer can be uniquely represented as a sum of powers of 2. For example:
13 = 8 + 4 + 1.Fenwick took this idea and applied it to prefix ranges: instead of storing every single element,
tree[i]stores the sum of a contiguous range of length equal to its lowest set bit!The length of the range responsible by index
iis given by:lowbit(i) = i & (-i).i = 12 (1100_2):lowbit(12) = 4. Sotree[12]stores the sum of 4 elements: indices[9, 10, 11, 12]!i = 8 (1000_2):lowbit(8) = 8. Sotree[8]stores the sum of the first 8 elements:[1 ... 8]!2. The Two Operations
A. Prefix Sum Query: `i -= (i & -i)`
To calculate the prefix sum up to index
13:tree[13](covers index 13).13 - lowbit(13) = 13 - 1 = 12.tree[12](covers indices 9 through 12).12 - lowbit(12) = 12 - 4 = 8.tree[8](covers indices 1 through 8).8 - lowbit(8) = 8 - 8 = 0(Done!).Total reads: only 3 steps to sum 13 numbers! At each step, you strip off one binary bit, taking at most
O(log N)operations.B. Point Update: `i += (i & -i)`
When you add delta to element
i, which parent ranges need to be updated? Every index whose range coversi! You navigate up the tree simply by adding the lowest set bit:i += (i & -i)!Clean C++20 Implementation
Why Fenwick Beats Segment Trees in Production