This page is the stress test for the parent Fenwick tree note. We will not just re-solve one nice example — we will build a matrix of every kind of situation a Fenwick tree can be asked about, then work through examples until every cell of that matrix is covered .
Before we start, one reminder of the two moves, because every single example below is just these two moves on repeat:
Recall The only two operations (from the parent note)
Query (prefix sum a 1 + ⋯ + a i ): start at i , add tree [ i ] , then set i ← i − lowbit ( i ) , repeat until i = 0 . (walks DOWN toward 0)
Update (add δ to a j ): start at j , add δ to tree [ j ] , then set j ← j + lowbit ( j ) , repeat while j ≤ n . (walks UP toward n )
lowbit ( i ) = i & ( − i ) = value of the lowest set bit. See Two's complement representation for why the negative-AND trick isolates that bit.
Here is every case class a Fenwick problem can throw at you. Each row is a distinct kind of trouble; the rightmost column names the worked example that nails it.
#
Case class
What could trip you
Example
A
Plain prefix query, positive values
pick the right jump path
Ex 1
B
Negative values in the array
sums can shrink, subtotals go negative
Ex 2
C
Point update , then re-query
which cells to fix
Ex 3
D
Range sum [ l , r ]
subtract query ( l − 1 ) not query ( l )
Ex 4
E
Boundary indices (i = 1 , i = n )
shortest and longest jump paths
Ex 5
F
Zero / degenerate (query ( 0 ) , empty range)
loops that never run
Ex 6
G
Whole-array sum
single cell tree [ n ] if n is a power of two
Ex 7
H
Real-world word problem (running bank balance)
model it as point-update + prefix
Ex 8
I
Exam twist : recover a single element a j
a j = query ( j ) − query ( j − 1 ) , or a slicker way
Ex 9
Throughout, unless a new array is stated, we use this fixed test array (1-indexed, n = 8 ):
a = [ 3 , 2 , − 1 , 6 , 5 , 4 , − 3 , 3 ]
The Fenwick cells for this array (built once) are:
query ( 7 ) = a 1 + ⋯ + a 7 .
Forecast: Guess how many cells the path visits before you read on. (Hint: count the 1-bits of 7 .)
Step 1. Write 7 = 11 1 2 . lowbit ( 7 ) = 1 , so add tree [ 7 ] and jump to 7 − 1 = 6 .
Why this step? Cell 7 owns exactly the block [ 7 , 7 ] , i.e. a 7 . What remains to sum is the prefix up to 6 .
Step 2. At 6 = 11 0 2 , lowbit ( 6 ) = 2 : add tree [ 6 ] , jump to 6 − 2 = 4 .
Why this step? Cell 6 owns [ 5 , 6 ] = a 5 + a 6 . Now we still need the prefix up to 4 .
Step 3. At 4 = 10 0 2 , lowbit ( 4 ) = 4 : add tree [ 4 ] , jump to 4 − 4 = 0 . Stop (i=0).
Why this step? Cell 4 owns [ 1 , 4 ] , the whole remaining front chunk. Hitting 0 means nothing is left.
So query ( 7 ) = tree [ 7 ] + tree [ 6 ] + tree [ 4 ] = ( − 3 ) + 9 + 10 = 16 .
Verify: Direct sum 3 + 2 − 1 + 6 + 5 + 4 − 3 = 16 . ✓ And 7 = 11 1 2 has three 1-bits — path length was exactly 3. ✓
query ( 3 ) = a 1 + a 2 + a 3 where a 3 = − 1 .
Forecast: Will the answer be bigger or smaller than query ( 2 ) = 5 ? Guess before computing.
Step 1. 3 = 01 1 2 , lowbit ( 3 ) = 1 : add tree [ 3 ] = − 1 , jump to 3 − 1 = 2 .
Why this step? Cell 3 owns block [ 3 , 3 ] = a 3 = − 1 . A negative subtotal is perfectly legal — the block sum just happens to be below zero.
Step 2. 2 = 01 0 2 , lowbit ( 2 ) = 2 : add tree [ 2 ] = 5 , jump to 2 − 2 = 0 . Stop.
Why this step? Cell 2 owns [ 1 , 2 ] = a 1 + a 2 = 5 , the whole remaining front.
query ( 3 ) = ( − 1 ) + 5 = 4 .
Verify: Direct 3 + 2 + ( − 1 ) = 4 . ✓ It is smaller than query ( 2 ) = 5 — the negative element pulled the prefix down. Fenwick handles negatives with zero special-casing because it only ever adds numbers.
a[3] += 10, then recompute query ( 3 ) and query ( 6 ) .
Forecast: Which cells change? Which prefixes change — does query ( 2 ) change?
Step 1. j = 3 = 01 1 2 : add 10 to tree [ 3 ] ; jump to 3 + lowbit ( 3 ) = 3 + 1 = 4 .
Why this step? Index 3 lives inside cell 3's block [ 3 , 3 ] , so that subtotal must grow by 10 .
Step 2. j = 4 = 10 0 2 : add 10 to tree [ 4 ] ; jump to 4 + 4 = 8 .
Why this step? Index 3 is inside block [ 1 , 4 ] owned by cell 4 — it also must grow.
Step 3. j = 8 = 100 0 2 : add 10 to tree [ 8 ] ; jump to 8 + 8 = 16 > n = 8 . Stop.
Why this step? Index 3 is inside [ 1 , 8 ] owned by cell 8. No larger cell exists, so we stop.
Now cells are tree [ 3 ] = 9 , tree [ 4 ] = 20 , tree [ 8 ] = 29 ; the rest unchanged.
Requery: query ( 3 ) = tree [ 3 ] + tree [ 2 ] = 9 + 5 = 14.
query ( 6 ) = tree [ 6 ] + tree [ 4 ] = 9 + 20 = 29.
Verify: New a 3 = 9 . Direct query ( 3 ) = 3 + 2 + 9 = 14 . ✓ Direct query ( 6 ) = 3 + 2 + 9 + 6 + 5 + 4 = 29 . ✓ And query ( 2 ) still uses only tree [ 2 ] , which we never touched — it stays 5 , correct because indices 1 , 2 are before the change. ✓
a[3]+=10 update from Ex 3, find the range sum of [ 3 , 6 ] .
Forecast: Should you subtract query ( 2 ) or query ( 3 ) ? Decide before Step 1.
Step 1. Range [ l , r ] = [ 3 , 6 ] equals query ( 6 ) − query ( l − 1 ) = query ( 6 ) − query ( 2 ) .
Why this step? query ( 6 ) is a 1 + … + a 6 ; we want to delete the part strictly before l = 3 , which is a 1 + a 2 = query ( 2 ) . Subtracting query ( 3 ) would wrongly delete a 3 too — the exact mistake called out in the parent note. This is the same trick as a Prefix sum array , just with O ( log n ) queries.
Step 2. From Ex 3, query ( 6 ) = 29 . Compute query ( 2 ) = tree [ 2 ] = 5 .
Step 3. Range = 29 − 5 = 24 .
Verify: Direct a 3 + a 4 + a 5 + a 6 = 9 + 6 + 5 + 4 = 24 . ✓ (With a 3 now = 9 .) Units sanity: it is a sum of the four requested elements, no more, no fewer.
query ( 1 ) and query ( 8 ) on the original array (before Ex 3's update).
Forecast: One of these visits a single cell; the other visits a single cell too — but for opposite reasons. Guess which cell each hits.
Part A — query ( 1 ) :
Step A1. 1 = 000 1 2 , lowbit ( 1 ) = 1 : add tree [ 1 ] = 3 , jump to 1 − 1 = 0 . Stop.
Why this step? Index 1 is the smallest possible; its block is exactly [ 1 , 1 ] . One cell, done.
query ( 1 ) = 3 .
Part B — query ( 8 ) :
Step B1. 8 = 100 0 2 , lowbit ( 8 ) = 8 : add tree [ 8 ] = 19 , jump to 8 − 8 = 0 . Stop.
Why this step? 8 is a power of two , so it has a single 1-bit — cell 8 already owns the whole prefix [ 1 , 8 ] . One cell, done.
query ( 8 ) = 19 .
Verify: query ( 1 ) = a 1 = 3 . ✓ query ( 8 ) = 3 + 2 − 1 + 6 + 5 + 4 − 3 + 3 = 19 . ✓ Both boundary queries were length-1 paths — the extremes are the cheapest , not the most expensive.
query ( 0 ) return, and what is the range sum of the empty range [ 4 , 3 ] (where l > r )?
Forecast: Will these crash, or return a clean number?
Step 1. query ( 0 ) : the loop condition is while i > 0. With i = 0 it never runs, so s stays 0 .
Why this step? lowbit ( 0 ) = 0 & 0 = 0 — index 0 has no lowest set bit, so there is nothing to strip and nothing to add. The parent note's warning ("Fenwick must be 1-indexed") is exactly this: index 0 is a dead end , which is why we deliberately use it as the "sum of nothing = 0" sentinel.
query ( 0 ) = 0 .
Step 2. Empty range [ 4 , 3 ] : apply the range formula query ( 3 ) − query ( 4 − 1 ) = query ( 3 ) − query ( 3 ) = 0 .
Why this step? An empty range contains no elements, so its sum must be 0 . The formula gives that automatically — no special case needed.
Verify: Sum of zero elements is 0 . ✓ The formula returning 0 for l = r + 1 is the sanity check that our telescoping is consistent even at the degenerate edge.
Worked example Get the total of all 8 elements two ways: via
query ( 8 ) , and by naming a single cell.
Forecast: Because n = 8 = 2 3 , one cell already holds the answer. Which one?
Step 1. query ( 8 ) — from Ex 5 (original array) this is 19 , a single-cell path landing on tree [ 8 ] .
Why this step? When n is a power of two, tree [ n ] owns block [ 1 , n ] = the entire array.
Step 2. So the whole-array sum is just tree [ 8 ] = 19 directly — no loop needed for this special n .
Why this step? Recognizing power-of-two n lets you read the grand total in O ( 1 ) . (For non-power-of-two n , you'd still need the full O ( log n ) query — do not over-generalize.)
Verify: ∑ a = 3 + 2 − 1 + 6 + 5 + 4 − 3 + 3 = 19 . ✓
Worked example A bank account starts empty. Over 8 days the day-changes are
a = [ 3 , 2 , − 1 , 6 , 5 , 4 , − 3 , 3 ] (thousands of ₹, negatives are withdrawals). Someone corrects day 3's entry with a[3] += 10. What is the balance at end of day 6?
Forecast: Balance at end of day 6 = prefix sum through day 6, after the correction. Guess the number.
Step 1. "Balance at end of day t " = a 1 + ⋯ + a t = query ( t ) . This is why a Fenwick tree fits: transactions are point updates (a day's amount changes), and balances are prefix queries .
Why this step? Modeling: each transaction touches one day; each balance query is a running total — precisely the two Fenwick operations, both O ( log n ) even if millions of days.
Step 2. Apply the correction: a[3] += 10 updates tree [ 3 ] , tree [ 4 ] , tree [ 8 ] (exactly Ex 3).
Step 3. Balance = query ( 6 ) = tree [ 6 ] + tree [ 4 ] = 9 + 20 = 29 (in thousands ₹).
Verify: Day-by-day after correction: 3 , 5 , 14 , 20 , 25 , 29 — end of day 6 is 29 . ✓ Units: thousands of ₹, a sum of daily ₹-changes, dimensionally consistent. So the balance is ₹29{,}000 .
Worked example Given only the Fenwick cells (original array), recover
a 7 and a 4 without rebuilding the array.
Forecast: a j = query ( j ) − query ( j − 1 ) always works. But for some j there is a shortcut using just cells. Which j ?
Step 1 (recover a 7 ). a 7 = query ( 7 ) − query ( 6 ) .
Why this step? query ( 7 ) − query ( 6 ) cancels a 1 + ⋯ + a 6 , leaving exactly a 7 . From Ex 1, query ( 7 ) = 16 ; and query ( 6 ) = tree [ 6 ] + tree [ 4 ] = 9 + 10 = 19 . So a 7 = 16 − 19 = − 3 .
Step 2 (recover a 4 , the slick way). For a 4 : lowbit ( 4 ) = 4 , so cell 4 owns block [ 1 , 4 ] . Then
a 4 = tree [ 4 ] − ( tree [ 3 ] + tree [ 2 ] ) = 10 − ( − 1 + 5 ) = 6.
Why this step? tree [ 4 ] sums [ 1 , 4 ] . To peel off a 4 alone, subtract the sub-cells covering [ 1 , 3 ] that sit "under" cell 4 — namely tree [ 3 ] (block [ 3 , 3 ] ) and tree [ 2 ] (block [ 1 , 2 ] ). This is faster than two full queries and is a classic exam trick; it mirrors how a Segment tree decomposes a node into children. (See also Order statistics and Inversion counting where recovering counts per index matters.)
Verify: Original array: a 7 = − 3 ✓ and a 4 = 6 ✓. Cross-check a 7 by the generic formula too — both routes agree.
Common mistake The recover-formula off-by-one
Writing a j = query ( j ) − query ( j ) (equals 0!) or query ( j + 1 ) − query ( j ) (that's a j + 1 ). The correct single element is query ( j ) − query ( j − 1 ) — subtract the prefix ending one before j .
Recall Quick self-test across the matrix
Cell B: is a negative subtotal a bug? ::: No — Fenwick only adds; negative block sums are fine.
Cell D: range [ l , r ] formula? ::: query(r) - query(l-1).
Cell F: what is query(0)? ::: 0 — the loop never runs; index 0 has no lowbit.
Cell G: when is the whole sum a single cell? ::: When n is a power of two, tree[n] owns [1,n].
Cell I: recover a single a_j generically? ::: a_j = query(j) - query(j-1).
Cell E: which query indices give length-1 paths? ::: i=1 and any power of two (single set bit).
Mnemonic For range vs element
"Range subtracts l − 1 ; element subtracts j − 1 ." Both peel off everything strictly before the left end — a Fenwick query is always a prefix, so differences are how you carve out any window.
Parent: Fenwick tree (Binary Indexed Tree) — prefix sums, O(log n) update and query (index 3.4.16)
Foundation for the range trick: Prefix sum array
Bit isolation behind lowbit : Two's complement representation , Binary representation of integers
A heavier alternative that also does these queries: Segment tree
Applications that reuse point-update + prefix: Inversion counting , Order statistics , Range update with difference array