~/data-structures/fenwick-tree
Fenwick tree (binary indexed tree)
Prefix sums that survive updates: change one element or sum any prefix in O(log n), with an array and ten lines of code.
tree[i] stores the sum of the lowbit(i) elements ending at i. A prefix sum hops down by clearing low bits; an update hops up by adding them.
An array gets point updates mixed with prefix or range sum queries, too many to rebuild prefix sums each time.
O(log n) per update or query, O(n log n) to build
O(n)
You’ll recognise it when
- An array changes one element at a time, and between changes you need sums of prefixes or ranges.
- Both kinds of operation come in large numbers, say 10⁵ each, so O(n) per operation is too slow.
- You count “how many earlier values are smaller than this one” while scanning: inversions, rank queries, smaller-after-self.
- The operation can be undone (sum, xor, count). Min and max can’t, which rules the Fenwick tree out for them.
It’s often confused with the segment tree. That does everything a Fenwick tree does and more (min, max, lazy range updates), at the cost of about four times the code. For sums, the Fenwick tree is the shorter tool.
The idea
Plain prefix sums answer any range sum in O(1), but one changed element shifts every prefix after it, and fixing them is O(n). Storing the raw array is the opposite: updates are free, sums are O(n). The Fenwick tree sits in between, with both at O(log n).
Think of money split across envelopes. Envelope 12 holds the takings of days 9 to 12, envelope 8 holds days 1 to 8, envelope 11 holds day 11 only. To total days 1 to 12 you open two envelopes, 12 and 8, not twelve. When day 3’s figure changes, you correct only the few envelopes whose span includes day 3: 3, 4 and 8.
Which envelope holds which days is decided by the binary form of its number. Take i, find its lowest set bit, call it lowbit(i). Then tree[i] holds the sum of the lowbit(i) elements ending at i, that is a[i − lowbit(i) + 1..i].
| i | binary | lowbit(i) | tree[i] sums |
|---|---|---|---|
| 6 | 0110 | 2 | a[5..6] |
| 8 | 1000 | 8 | a[1..8] |
| 11 | 1011 | 1 | a[11] |
| 12 | 1100 | 4 | a[9..12] |
In code, lowbit(i) is i & -i. In two’s complement, -i is ~i + 1: flipping every bit turns the trailing zeros into ones, and the +1 carries through them back to zeros, stopping at the lowest set bit. So i and -i agree on that bit and on nothing above it. For 12 = 01100, -12 ends in …10100, and 12 & -12 = 00100 = 4.
How it works
The array is 1-indexed: position 0 has no set bit, so it would cover zero elements and the loops below would never move. Scroll through the steps and the graphic follows along; the bottom rows show each i in binary with its lowest set bit bright. You can also edit the array and the operations, or roll a random input.
- Each bar is one
tree[i], drawn under the positions it sums. Oddihas lowbit 1, so its bar is one cell wide; 12 = 1100₂ has lowbit 4, sotree[12]covers positions 9 to 12. - Prefix sum. To add up
a[1..11], start ati = 11and addtree[11]tototal. - Then clear the lowest set bit,
i -= i & -i: 1011 becomes 1010, soi = 10. The bar you just added covered exactly what lay between 10 and 11, soa[1..10]is all that’s left. - Repeat until
iis 0. Positions 1 to 11 came from three bars,tree[11] + tree[10] + tree[8], one per set bit of 11. - Update. To add 4 to
a[3], every bar containing position 3 must grow by 4. Start attree[3]. - Move up with
i += i & -i: 3 = 0011 becomes 0100, soi = 4. Adding the lowest bit jumps to the next bar that reaches further left, far enough to include position 3. - From 4 = 0100 the jump goes to 8, then to 16, which is past the end. The dashed line crosses exactly the bars 3, 4 and 8, and those are the ones that changed.
- Range sum.
range_sum(l, r)isprefix_sum(r) − prefix_sum(l − 1): two walks down, one subtraction.
Why it’s correct: clearing the lowest bit of i gives i − lowbit(i), which is exactly where tree[i]’s range starts (minus one), so the bars visited by a query sit side by side and tile [1, i] with no gaps or overlaps. For updates, adding the lowest bit of i lands on the smallest index above i whose bar is long enough to still reach back past i; every bar that contains position p lies on that chain, and no other bar does.
class Fenwick:
"""Point updates and prefix sums in O(log n). Positions are 1..n."""
def __init__(self, values):
self.n = len(values)
# tree[i] holds a range sum; tree[0] is unused.
self.tree = [0] * (self.n + 1)
for i, x in enumerate(values, start=1):
self.update(i, x)
def update(self, i, delta):
"""a[i] += delta: fix every node whose range contains i."""
while i <= self.n:
self.tree[i] += delta
i += i & -i
def prefix_sum(self, i):
"""a[1] + a[2] + ... + a[i]."""
total = 0
while i > 0:
total += self.tree[i]
i -= i & -i
return total
def range_sum(self, l, r):
"""a[l] + ... + a[r]."""
return self.prefix_sum(r) - self.prefix_sum(l - 1)#include <vector>
using namespace std;
// Point updates and prefix sums in O(log n). Positions are 1..n.
struct Fenwick {
int n;
vector<long long> tree; // tree[0] is unused
explicit Fenwick(const vector<long long>& values)
: n(values.size()), tree(values.size() + 1, 0) {
for (int i = 1; i <= n; i++) update(i, values[i - 1]);
}
// a[i] += delta: fix every node whose range contains i.
void update(int i, long long delta) {
while (i <= n) {
tree[i] += delta;
i += i & -i;
}
}
// a[1] + a[2] + ... + a[i].
long long prefixSum(int i) const {
long long total = 0;
while (i > 0) {
total += tree[i];
i -= i & -i;
}
return total;
}
// a[l] + ... + a[r].
long long rangeSum(int l, int r) const {
return prefixSum(r) - prefixSum(l - 1);
}
};// Point updates and prefix sums in O(log n). Positions are 1..n.
class Fenwick {
private final int n;
private final long[] tree; // tree[0] is unused
Fenwick(long[] values) {
n = values.length;
tree = new long[n + 1];
for (int i = 1; i <= n; i++) update(i, values[i - 1]);
}
// a[i] += delta: fix every node whose range contains i.
void update(int i, long delta) {
while (i <= n) {
tree[i] += delta;
i += i & -i;
}
}
// a[1] + a[2] + ... + a[i].
long prefixSum(int i) {
long total = 0;
while (i > 0) {
total += tree[i];
i -= i & -i;
}
return total;
}
// a[l] + ... + a[r].
long rangeSum(int l, int r) {
return prefixSum(r) - prefixSum(l - 1);
}
}Why it’s O(log n)
A query clears one set bit per step, and i has at most ⌊log₂ n⌋ + 1 set bits. An update adds the lowest bit, which makes the lowest set bit at least twice as big each step, so after at most log₂ n steps i passes n.
| n | steps per operation, worst case |
|---|---|
| 1,000 | 10 |
| 1,000,000 | 20 |
| 1,000,000,000 | 30 |
Building by calling update for every element is O(n log n). The structure is one array of n + 1 numbers, so space is O(n).
Common mistakes
Using index 0
0 & -0 is 0, so an update at position 0 adds nothing to i and loops forever, and a query at 0 returns 0 without looking. Keep the tree 1-indexed and shift 0-indexed input by one.
fw.update(i, x) # ✗ i from enumerate(a), starts at 0
fw.update(i + 1, x) # ✓ positions 1..n
Off by one in range sums
The range [l, r] is everything up to r minus everything before l, which is prefix_sum(l − 1), not prefix_sum(l).
fw.prefix_sum(r) - fw.prefix_sum(l) # ✗ drops a[l]
fw.prefix_sum(r) - fw.prefix_sum(l - 1) # ✓
32-bit totals
With 2·10⁵ values up to 10⁹, a prefix sum reaches 2·10¹⁴, far past int. In C++ and Java, make both the tree and the total long long / long.
vector<int> tree; // ✗ overflows silently
vector<long long> tree; // ✓
Setting a value with update
update(i, delta) adds. To set a[i] = v, you need the old value: keep a copy of the array and call update(i, v − a[i]), then store a[i] = v.
Variations
- Range update, point query. Store the difference array instead: adding
vtoa[l..r]isupdate(l, v)andupdate(r + 1, −v), anda[i]isprefix_sum(i). Range update and range sum needs two trees. - Counting inversions. Compress values to ranks 1..m, scan right to left, and for each value add
prefix_sum(rank − 1)(how many smaller values sit to its right) beforeupdate(rank, 1). O(n log n) in total. - 2-D Fenwick tree. Nest the loops:
tree[x][y]over both coordinates gives rectangle sums on a grid with point updates in O(log n · log m). - Linear build and binary lifting. Copy the array into
tree, then for eachiaddtree[i]intotree[i + lowbit(i)]: O(n). And to find the first position where the prefix sum reachesk, walk down powers of two from the top instead of binary searching overprefix_sum: O(log n). - Segment tree. When you need min, max or lazy range assignments, use a segment tree: it stores every range explicitly, so it doesn’t need to subtract.
Check yourself
5 quick questions. Pick an answer to see why it's right or wrong.
-
1
An array of 2·10⁵ numbers receives 2·10⁵ operations, each either
a[i] += vor “sum ofa[l..r]”, in any order. Which approach fits best?A Fenwick tree does a point update and a prefix sum in O(log n) each, and a range sum is two prefix sums. Rebuilding prefix sums costs O(n) per update, about 4·10¹⁰ steps in the worst case. A sparse table can’t be updated at all.
-
2
What does this print?
print([i & -i for i in [6, 8, 12, 7]])i & -ikeeps only the lowest set bit: 6 = 110 gives 2, 8 = 1000 gives 8, 12 = 1100 gives 4, 7 = 111 gives 1. It’s also how many elementstree[i]covers. The tempting8for 12 is its highest bit, not its lowest. -
3
This update hangs when called as
update(0, 5). Why?def update(i, delta):while i <= n:tree[i] += deltai += i & -iEvery step adds the lowest set bit of
i, and 0 has none, so the loop spins on index 0 forever. Shift 0-indexed positions by one (update(i + 1, delta)). Changing the loop bound doesn’t help:istill never moves. -
4
What does this print?
def count_inversions(a):ranks = {v: i + 1 for i, v in enumerate(sorted(set(a)))}m = len(ranks)tree = [0] * (m + 1)inversions = 0for x in reversed(a):i, seen = ranks[x] - 1, 0 # smaller values already seenwhile i > 0:seen += tree[i]i -= i & -iinversions += seeni = ranks[x]while i <= m:tree[i] += 1i += i & -ireturn inversionsprint(count_inversions([3, 1, 2]), count_inversions([2, 2, 1]))Scanning right to left, each value adds how many values already seen (to its right) are strictly smaller, a prefix sum up to
rank - 1. [3, 1, 2] has the inversions (3,1) and (3,2); [2, 2, 1] has (2,1) twice. Querying up torankinstead would count the equal pair of 2s and give 3. -
5
Why can’t a plain Fenwick tree answer “minimum of
a[l..r]” with point updates, the way it answers range sums?Sums and xor can be undone, so two prefixes give any range. Knowing the minimum of
a[1..r]and ofa[1..l-1]tells you nothing abouta[l..r]. For range min or max with updates, use a segment tree. Minimum is associative; that isn’t the problem.