skip to content

In a Fenwick tree, why does stripping index i's lowest set bit walk exactly one prefix?

level: middleimportance: should knowfreq 38%

answer

  1. look at the binary spelling of the index
  2. each node owns a power-of-two block
  3. how far down does node i's block reach?
  4. the next index is the last one not yet covered
  5. steps equal the number of 1-bits in i

basics

~20 s

In a Fenwick tree, node i aggregates the lowbit(i) positions ending at i. Stripping that low bit lands on the last position the node did not cover, so successive nodes tile the prefix with no gap and no overlap.

solid answer

~50 s

A Fenwick tree is 1-indexed, and node `i` holds the aggregate of the half-open block `(i - lowbit(i), i]` — that is, the `lowbit(i)` positions ending at `i`, where `lowbit(i) = i & (-i)` isolates the lowest set bit. So after adding node `i` to the running answer, everything from `i - lowbit(i) + 1` through `i` is accounted for, and the next uncovered position is exactly `i - lowbit(i)`. Jumping there and repeating tiles the prefix `1..i` perfectly. Because each step clears one set bit of `i`, the loop runs once per 1-bit in `i` — at most ⌊log₂ n⌋ + 1 steps. Point updates walk the other direction, `i = i + lowbit(i)`, visiting the nodes whose block contains `i`. The whole structure is n words and two short loops, which is why it is the compact choice for mutable prefix sums.

code

pseudocode · 12 lines
pseudocode
prefix(i):                       // aggregate of positions 1..i
    s = 0
    while i > 0:
        s = s + tree[i]
        i = i - (i & (-i))       // drop lowest set bit
    return s

update(i, delta):                // add delta at position i
    while i <= n:
        tree[i] = tree[i] + delta
        i = i + (i & (-i))       // next node whose block contains i
    return

go deeper

for a junior

Recall the shape: a companion array of n entries, 1-indexed, with prefix queries and point updates both in O(log n). Knowing that the index's binary form drives the walk is enough at this level.

for a middle

State the invariant precisely — node i holds the lowbit(i) positions ending at i — and walk a concrete index such as 13 out loud to show the blocks tile the prefix exactly. Name popcount(i) as the step count.

for a senior

Show the operational side: the loops fail silently when a direction is reversed, so correctness comes from randomised testing against a brute-force scan, and the compact n-word footprint is the reason to prefer it when the aggregate is a sum.

for a principal

Own the tradeoff this compactness buys and costs: minimal memory and very tight loops, at the price of being tied to invertible aggregates and prefix-shaped decomposition. Be ready to say when that ceiling makes it the wrong library default.

## What each node owns A Fenwick tree (also called a binary indexed tree) over a series of length n uses a companion array of n entries, indexed from 1. Entry `i` does **not** store position `i`'s value and does **not** store the prefix up to `i`. It stores the aggregate of a *block*: the `lowbit(i)` positions ending at `i`, written as the half-open range `(i - lowbit(i), i]`. `lowbit(i) = i & (-i)` isolates the lowest set bit of `i`. Under two's-complement negation, `-i` is `~i + 1`, which leaves the lowest set bit in place and flips everything above it, so the bitwise AND keeps exactly that one bit. Concretely: | i | binary | lowbit | block covered | |---|---|---|---| | 1 | 0001 | 1 | position 1 | | 6 | 0110 | 2 | positions 5–6 | | 8 | 1000 | 8 | positions 1–8 | | 12 | 1100 | 4 | positions 9–12 | | 13 | 1101 | 1 | position 13 | So blocks come in power-of-two sizes, and which size a node gets is dictated by the binary spelling of its own index. Odd indices own a single position; the highest power of two ≤ n owns the entire first half. ## Why the descent tiles the prefix To get the aggregate of `1..i`, start with `i` and repeatedly take the node's value and strip the low bit: - Node `i` covers down to `i - lowbit(i) + 1`. - Everything strictly below that is still missing, and the largest missing index is `i - lowbit(i)`. - So jump there. That is exactly what `i = i - (i & (-i))` does. The blocks therefore abut perfectly: no position is counted twice, none is skipped. **Walk it on 13** (binary 1101): 1. `i = 13`, lowbit 1 → node 13 covers position 13. Jump to 12. 2. `i = 12` (1100), lowbit 4 → node 12 covers positions 9–12. Jump to 8. 3. `i = 8` (1000), lowbit 8 → node 8 covers positions 1–8. Jump to 0, stop. Three nodes: 1 + 4 + 8 = 13 positions, exactly the prefix. And three is precisely the number of 1-bits in 13 — because each step clears one. That is the complexity bound: **the query visits popcount(i) nodes, at most ⌊log₂ n⌋ + 1**. The binary expansion of `i` *is* the decomposition of the prefix into blocks. ## The update walks the other way Adding a delta at position `i` must repair every node whose block contains `i`. Those are found by `i = i + lowbit(i)`, repeated while `i ≤ n`. From position 5: 5 → 6 → 8 → 16 → … Each step moves to the next node upward whose block swallows the previous one, and there are again at most log n of them. It is worth noticing the asymmetry — descending strips bits, ascending adds them — and that neither loop involves comparisons, pointers, or recursion. ## Range queries, and the requirement hiding in them A Fenwick tree natively answers *prefixes*. An arbitrary range `l..r` is answered by `prefix(r) - prefix(l-1)`. That subtraction is not free: it demands that the aggregate operation be **invertible**. Sums qualify; so do bitwise XOR and counts. Minimum and maximum do not, which is why an arbitrary range-minimum query is not something a plain Fenwick tree can serve. ## Practical notes - **1-indexing is structural, not stylistic.** `lowbit(0)` is 0, so a 0 index would loop forever on the update path and terminate instantly on the query path. Series positions are mapped to `1..n`. - **Space is n words** — no child pointers, no padding to a power of two, roughly a quarter to a half of what a segment tree's array layout takes. - **A linear build exists.** Rather than n separate updates costing O(n log n), fill the array with the raw values and then, for each `i` ascending, push `tree[i]` into `tree[i + lowbit(i)]` when that index is in range. One pass, O(n). - **The failure mode is silent.** Reverse a direction — strip bits on the update or add them on the query — and the structure still returns numbers, just wrong ones, and often right for small indices. Test against a brute-force scan over random operation sequences rather than against hand-picked examples. ## What an interviewer is listening for Not the two loops, which are four lines each and easy to memorise, but the sentence that explains them: *node i covers the lowbit(i) positions ending at i, so stripping the low bit lands on the last position not yet covered.* Everything else — the popcount bound, the perfect tiling, the direction of the update — falls out of that one invariant.

  • Why must a Fenwick tree be 1-indexed?
    Because `lowbit(0)` is 0. On the query path index 0 is the natural terminator, but on the update path adding a zero low bit would never advance, so a position stored at index 0 would loop forever or never be reached. Mapping the series onto `1..n` keeps both loops well defined; the offset is part of the structure, not a convention.
  • How do you answer a range aggregate rather than a prefix, and what does that assume?
    Compute `prefix(r) - prefix(l-1)`. The subtraction assumes the aggregate is invertible — that knowing the total of `1..r` and of `1..l-1` determines the total of `l..r`. Sums, counts and XOR satisfy this; minimum and maximum do not, so those ranges need a structure that combines covering blocks instead of subtracting prefixes.
  • Can you build a Fenwick tree over n existing values faster than n separate updates?
    Yes, in O(n) instead of O(n log n). Copy the raw values into the array, then for each `i` ascending add `tree[i]` into `tree[i + lowbit(i)]` whenever that index is within range. Each entry is pushed into its immediate parent block exactly once, so a single linear pass leaves every node holding its correct block aggregate.

Paying an exact amount with coins that only come in powers of two: the 1-bits of the number tell you precisely which denominations to hand over, and each coin you place covers the next chunk of the total with nothing left over.

saying these in an interview costs you the question

  • Says node i stores the prefix up to i
  • Says node i stores just the value at position i
  • Claims every query visits exactly log n nodes
  • Uses the same bit direction for query and update
  • Assumes it answers range minimum like range sum

context