cf.completefrontend
ADVANCED DATA STRUCTURES · ADVANCED

Fenwick tree

A compact array that keeps running totals so you can add to one item and get any prefix sum in O(log n).

Time O(log n) per add or prefix sumSpace O(n)7 practice problemsStep-through picture

The idea

A Fenwick tree, also called a binary indexed tree, solves the same problem as a segment tree for sums: change single items and ask for range sums, both in O(log n). It is shorter to write and uses an array of just n + 1 numbers.

Each cell tree[i] (counting from 1) stores the sum of a block of items that ends at item i. The block's length is the lowest set bit of i in binary, written i & -i. For example tree[6] covers 2 items (6 is 110), tree[8] covers 8 items (8 is 1000), and tree[7] covers 1 item.

To get the sum of the first i items, add tree[i], then jump to the item just before that block (i -= i & -i), and repeat. To add to an item, update every block that contains it by jumping the other way (i += i & -i). Both walks take about log n jumps.

An everyday example

Counting pages with bookmarks

A long notebook has bookmarks of different sizes: some cover 1 page, some 2, some 4, some 8, and each bookmark has the total of the numbers on the pages it covers written on it. To total the first 7 pages, you read the bookmark for page 7 (1 page), then the one for pages 5 to 6, then the one for pages 1 to 4: three bookmarks instead of seven pages. When page 3 changes, you fix only the bookmarks that cover page 3.

How the example maps to the code
In the exampleIn the code
A bookmark and its totaltree[i]
How many pages a bookmark coversi & -i, the lowest set bit
Jumping to the bookmark before this onei -= i & -i
Fixing every bookmark that covers a pagei += i & -i

From the slow way to fenwick tree

  1. The problem is the same as for a segment tree: change single items and ask for range sums, many times, mixed together. A prefix-sum array answers in one step but needs up to n steps per change. A segment tree does both in O(log n), but it needs 4n slots and a few recursive methods. Can a plain array of n numbers do the same job?
  2. Look at how a prefix is made of blocks. Any whole number is a sum of powers of two: 7 = 4 + 2 + 1. So the first 7 items split into a block of 4 (items 1 to 4), a block of 2 (items 5 to 6), and a block of 1 (item 7). If each of those block sums were stored, a prefix sum would be just 3 additions, one per 1 bit in the binary form of 7.
  3. Which block should position i store? Let tree[i] hold the block that ends at item i and is as long as the lowest set bit of i, written i & -i. Every position stores exactly one block, so the array has n + 1 cells, and the blocks a prefix needs are found by taking tree[i] and then jumping to i - (i & -i), which drops the lowest 1 bit.
  4. When one item changes, only the blocks that contain it need fixing. Starting at its position and jumping i += i & -i visits exactly those blocks, each longer than the last, so there are at most about log₂ n of them. One array, two short loops, and the lowest-set-bit trick: that is a Fenwick tree.

How it works

  1. Create tree with n + 1 zeros. Index 0 is unused, because the jumps rely on 1-based positions.
  2. add(index, delta): start at i = index + 1 and add delta to tree[i].
  3. Move to the next block that also contains this item: i += i & -i. Stop when i passes the end.
  4. prefixSum(index): start at i = index + 1 with total = 0. Add tree[i].
  5. Move to the block just before: i -= i & -i. Stop when i reaches 0, and return total.
  6. rangeSum(left, right) is prefixSum(right) minus prefixSum(left - 1).

Watch it run

This picture runs the code below on a real input. Press Step to move one step at a time, or Play to watch. The highlighted line is the one that just ran. Change the input to see other cases.

Loading the picture…
See every step at onceThe same run, laid out side by side
Drawing every step…

The code

Point at a note to light up the lines it explains.

  1. class FenwickTree {
  2. constructor(n) {
  3. this.tree = new Array(n + 1).fill(0);
  4. }
  5. add(index, delta) {
  6. for (let i = index + 1; i < this.tree.length; i += i & -i) {
  7. this.tree[i] += delta;
  8. }
  9. }
  10. prefixSum(index) {
  11. let total = 0;
  12. for (let i = index + 1; i > 0; i -= i & -i) {
  13. total += this.tree[i];
  14. }
  15. return total;
  16. }
  17. rangeSum(left, right) {
  18. return this.prefixSum(right) - (left > 0 ? this.prefixSum(left - 1) : 0);
  19. }
  20. }

How fast it is

TimeO(log n) per add or prefix sum
Extra memoryO(n)

Each jump changes the lowest set bit of i, so a walk has at most about log₂ n jumps. The tree is one array of n + 1 numbers.

  • Best caseO(1)

    prefixSum(0) reads only tree[1], then i becomes 0. An add to a position whose next jump is past the end also takes one step.

  • Average caseO(log n)

    A prefixSum takes one step per 1 bit in index + 1, about half of the log₂ n bits for a random index.

  • Worst caseO(log n)

    Positions with many 1 bits for prefixSum, such as 511 (111111111), and add at position 1, which climbs 1, 2, 4, 8, and so on. For 1,000 items, a prefix sum takes at most 9 jumps and an add at most 10.

Common mistakes

  • Using 0-based positions inside the loops. 0 & -0 is 0, so i never moves and the loop runs forever. Shift to 1-based with index + 1.
  • Setting a value with add(index, value) instead of add(index, value - current). A Fenwick tree adds changes; keep the current values in a separate array if you need to set.
  • Using it for min or max with updates that can make values bigger and smaller. Sums can be undone by subtracting, but a minimum can't; use a segment tree there.
  • Forgetting the left > 0 check, which calls prefixSum(-1).

When to use it

Look for these clues in a problem:

  • You need prefix sums or range sums while single items keep changing.
  • You need to count, for each item, how many earlier items are smaller (inversions, ranks), often after compressing values to small indexes.
  • You need to add to a range and read single items (store differences in the tree).
  • Memory or code size matters, and the operation is a sum (or anything you can undo, like XOR).

Check yourself

Answer each one in your head first, then open it.

Which cells does add(2, 5) change when there are 7 items?

tree[3] and tree[4]. The next jump goes to position 8, which doesn't exist for 7 items, so the loop stops.

Which items does tree[6] cover?

Positions 5 and 6, which are indexes 4 and 5, because 6 & -6 is 2: a block of 2 that ends at position 6.

Why does prefixSum(6) take exactly 3 jumps?

It starts at position 7, which is 111 in binary. Each jump removes one 1 bit (7, then 6, then 4, then 0), so it takes as many jumps as there are 1 bits.

Why can a Fenwick tree answer range sums but not range minimums?

A range sum is prefixSum(right) - prefixSum(left - 1). There is no way to "subtract" the minimum of the first part from the minimum of a longer part to get the minimum of what's left.

Practice problems

Stuck on one? Tuto is in the playground too, and gives you hints, never the answer.

Go further

You don't need these to start practicing. Open one when you want more.

Why it works

The reasoning that makes it always right

The tree keeps one property: tree[i] is the sum of the items at positions i - (i & -i) + 1 to i, counting positions from 1. When the tree is all zeros, every block sum is 0, so it holds. Every later change goes through add, which must keep it.

prefixSum is right because its blocks fit together. The block at i starts at i - (i & -i) + 1, and the next jump goes to i - (i & -i), whose block ends exactly one position before. So the blocks visited touch end to end, never overlap, and stop at position 1 when i reaches 0. Their sum is the sum of positions 1 to index + 1, which is items 0 to index.

add is right because it visits exactly the blocks that contain the item. A block ending at i contains position p when i >= p and the block reaches back far enough. Adding the lowest set bit to i gives the next position whose block is long enough to reach back over the current block, and so over p. Positions in between have shorter blocks that start after position i, so they can't contain p. Each jump makes the lowest set bit bigger, so there are at most about log₂ n jumps, and the loop ends when i passes the end.

Going deeper

3 more ideas

What i & -i means

In binary, -i flips all bits of i and adds one, so i & -i keeps only the lowest 1 bit of i. For i = 6 (110) it is 2 (10); for i = 8 (1000) it is 8; for any odd i it is 1. Cell tree[i] covers exactly that many items, ending at item i.

Cost

Each jump in prefixSum removes the lowest set bit of i, and each jump in add moves the lowest set bit up, so both loops run at most about log₂ n times. Building by calling add for every item is O(n log n). The array has n + 1 numbers: O(n) space.

Range updates with point reads

Store differences instead of values: to add v to items l to r, call add(l, v) and add(r + 1, -v). Then prefixSum(i) is the current value of item i. This is the difference-array idea, made fast for many updates and reads mixed together.

Work it by hand

Every step in a table, with why

Seven numbers are already added, so tree = [0, 6, 4, 4, 9, 3, 8, -1]. Add 5 to index 2, then ask for the sum of indexes 2 to 6. Each row is one turn of a loop.

nums = [6, -2, 4, 1, 3, 5, -1], add(2, 5), then rangeSum(2, 6)

StepCallii & -itree[i]totalWhat happensWhy
1add(2, 5)314 to 9-next i = 4Index 2 lives at position 3. tree[3] covers 1 item, item 3 itself, so it gets +5.
2add(2, 5)449 to 14-next i = 83 + 1 = 4. tree[4] covers positions 1 to 4, which include position 3, so it gets +5 too.
3add(2, 5)8---8 is not < 8: stopThere is no tree[8] for 7 items, so every block holding index 2 is now fixed.
4prefixSum(6)71-1-1next i = 6Index 6 is position 7. tree[7] covers only position 7.
5prefixSum(6)6287next i = 47 - 1 = 6. tree[6] covers positions 5 and 6: 3 + 5 = 8.
6prefixSum(6)441421next i = 06 - 2 = 4. tree[4] covers positions 1 to 4, already including the +5.
7prefixSum(6)0--21i > 0 fails: return 21Three blocks, 7, 5..6, and 1..4, covered every position from 1 to 7 exactly once.
8prefixSum(1)2244next i = 0left = 2, so subtract prefixSum(1). Position 2's block covers positions 1 and 2: 6 + (-2) = 4.
9prefixSum(1)0--4return 4One block was enough. rangeSum returns 21 - 4 = 17.

rangeSum(2, 6) returns 17, which matches 9 + 1 + 3 + 5 + (-1) after the change. The add touched 2 cells, and the two prefix sums read 3 cells and 1 cell, because 7 is 111 in binary and 2 is 10.

Compared with other ways

When to pick something else
ApproachTimeExtra memoryChoose it when
Fenwick treeO(log n)O(n)Per add or prefix sum. Pick it for sums (or XOR, or counts) with single-item changes: shortest code and n + 1 numbers.
Segment treeO(log n)O(n)You need min or max, which can't be subtracted, or lazy range updates, or a node that stores several values.
Prefix-sum arrayO(n)O(n)That O(n) is the cost of a change; a query is O(1). Pick it when the data rarely changes.
Square-root blocksO(sqrt n)O(n)You need an operation that doesn't fit either tree, and sqrt n steps per query is fast enough. Split the array into blocks of about sqrt n items with one total each.

Extra memory: O(n): one array of n + 1 numbers, no recursion, and no other memory.

How the steps grow

1101001k10k100k1M116324864input size n
Steps as the input grows, for Fenwick tree and the other approaches, on a scale where each line up is 10 times more steps.
  • Fenwick tree, Segment tree O(log n)
  • Prefix-sum array O(n)
  • Square-root blocks O(sqrt n)
About how many steps for bigger inputs
Approachn = 10n = 1,000n = 1,000,000
Fenwick tree31020
Segment tree31020
Prefix-sum array101,0001 million
Square-root blocks3321,000

Inputs that need care

5 tricky inputs
An index past the end, such as prefixSum(7) with 7 items
It reads tree[8], which is undefined, so total becomes NaN. The code doesn't check bounds; make sure index < n before calling.
An empty tree, new FenwickTree(0)
add does nothing because 1 < 1 is false, but prefixSum(0) reads tree[1] and returns NaN. Check for n === 0 first.
left = 0 in rangeSum
The left > 0 check skips the subtraction, so rangeSum(0, right) is just prefixSum(right). Without that check it would call prefixSum(-1).
Negative values, such as -2 and -1 above
Nothing changes: the blocks just store sums, and sums of negative numbers work the same way.
Decimal values, such as prices like 0.1
Floating-point sums drift a little after many adds. Store whole numbers, such as cents, when the totals must be exact.

Variations and follow-ups

Twists interviewers add

Build in O(n)

Instead of calling add for every item, which costs O(n log n), copy the items into tree[1..n], then for each i from 1 to n add tree[i] into tree[i + (i & -i)] if that position exists. For the trace's seven numbers this gives the same [0, 6, 4, 4, 9, 3, 8, -1].

Range add with range sum

Keep two Fenwick trees, one for differences and one for differences times their position. A range add becomes four add calls, and a range sum becomes a few prefix sums combined with a short formula. Everything stays O(log n).

Counting smaller items before each item

Map values to small ranks, walk the list from left to right, and for each value ask prefixSum(rank - 1) before calling add(rank, 1). The answers count, for each item, how many earlier items are smaller. Summing the opposite counts gives the number of inversions.

Find the first prefix that reaches a total

To find the smallest index whose prefix sum is at least x (all values non-negative), walk down powers of two from the largest: jump forward by a power whenever that block's sum still fits under x. This finds the answer in O(log n) without a separate binary search.

In an interview

Spot it, explain it, answer follow-ups
  • Spot it from "prefix sum" or "range sum" with "update an item", or from "for each item, count earlier items that are smaller", which becomes a Fenwick tree over value ranks.
  • Explain i & -i with one example, such as 6 (110) giving 2, and say what block tree[6] covers: positions 5 and 6. Then the two loops are easy to follow.
  • Test rangeSum(0, 0), the whole range, and a range right after an add inside it. Also say out loud why positions start at 1: 0 & -0 is 0, so a loop at position 0 would never move.
  • A usual follow-up is "can it do range minimum?". Answer no, not with this trick: a range sum is a difference of two prefix sums, but a minimum can't be subtracted. Use a segment tree or a sparse table.

Where frontend code uses it

The same idea in real UI code
  • A virtualized list with resizable rows can store row heights in a Fenwick tree: the offset of row k is a prefix sum, and resizing one row is a single add.
  • Analytics dashboards that count events per time bucket while events keep arriving can answer "events between minute a and minute b" with two prefix sums.
  • Ranking features, such as showing "you are faster than 83% of players" while scores stream in, count how many scores are below a value with a Fenwick tree over score buckets.

Related algorithms