03
Range update, range query
Two Fenwick Trees — what they store, and why it works.
Goal: add a value to every element in an interval, and later calculate the sum of any interval. We will build this from the difference-array idea rather than starting with a formula to memorise.
Step 1 — Represent the array by its changes
Let D[i] = A[i] − A[i−1], with A[0] = 0. In other words, D[i] records how much the array changes when we move from position i−1 to position i.
The original value at position i is the sum of all changes up to i:
A[i] = D[1] + D[2] + ··· + D[i]
This is exactly a prefix sum, so a BIT storing D can answer point-value queries.
Now consider adding +3 to positions 2 through 4 of an initially zero array:
index1
index2
index3
index4
index5
Only two differences change: D[2] increases by 3, and D[5] decreases by 3. The second change cancels the addition immediately after the interval.
D[2] += 3 and D[5] −= 3
Step 2 — Why one BIT is not enough for range sums
To find A[i], we sum the differences up to i. But a prefix sum of array values adds those answers together:
P[x] = A[1] + A[2] + ··· + A[x]
Think about one difference D[i]. It contributes to every array value from A[i] onwards. Within the prefix ending at x, it is therefore counted once for A[i], once for A[i+1], and so on through A[x] — a total of x − i + 1 times.
So each difference contributes its value multiplied by the number of times it appears:
P[x] = Σ (x − i + 1) · D[i], for i = 1 … x
Split the multiplier into two parts: x − i + 1 = x − (i − 1). Distributing gives:
P[x] = x · ΣD[i] − Σ((i − 1) · D[i])
That split is the whole trick. We need two prefix sums: the sum of D[i], and the sum of (i−1)·D[i].
BIT 1 — stores the differences
At each index i, the underlying value is D[i]. Its prefix query gives the sum of differences through x, which is the current array value A[x].
B₁ stores D[i]
Its prefix sum supplies the first quantity in the prefix-sum formula.
BIT 2 — stores weighted differences
At each index i, the underlying value is the difference multiplied by one less than its index: (i−1)·D[i].
B₂ stores (i − 1) · D[i]
Its prefix sum supplies the correction term that accounts for how long each difference contributes.
Step 3 — Put the two prefix sums together
Let sum(B, x) mean “the prefix sum through x in BIT B”. The derivation above now becomes a direct recipe:
P[x] = x · sum(B₁, x) − sum(B₂, x)
To get the sum from l through r, subtract the prefix ending just before l:
sum(l … r) = P[r] − P[l − 1]
Each interval addition updates both BITs at the same two difference boundaries. At a boundary i, if the difference changes by Δ, BIT 1 receives Δ and BIT 2 receives (i−1)·Δ. Each boundary update costs O(log n).
Worked check — add +3 to positions 2 through 4
After the update, D[2] = +3 and D[5] = −3; all other differences are zero. Thus BIT 1's underlying values are +3 at index 2 and −3 at index 5. BIT 2's underlying values are (2−1)·3 = +3 at index 2 and (5−1)·(−3) = −12 at index 5.
| Prefix x | sum(B₁, x) | sum(B₂, x) | P[x] = x·sum(B₁,x) − sum(B₂,x) |
| 3 | 3 | 3 | 3 × 3 − 3 = 6 |
| 4 | 3 | 3 | 4 × 3 − 3 = 9 |
| 5 | 0 | −9 | 5 × 0 − (−9) = 9 |
Check against the actual array [0, 3, 3, 3, 0]: its prefix sums at positions 3, 4, and 5 are 6, 9, and 9. The formula matches each one.
What exactly happens when an interval update reaches the two BITs?
For an addition of Δ on [l, r], the difference array receives +Δ at l and −Δ at r+1. For each of those two changes, update BIT 1 with the difference change itself, and BIT 2 with the change multiplied by (index−1). Both BITs are ordinary Fenwick Trees; only the values supplied to them differ.
Indexing matters: this page uses one-based indices, D[i] = A[i]−A[i−1], and BIT 2 stores (i−1)·D[i]. With these exact definitions, the prefix formula is P[x] = x·sum(B₁,x) − sum(B₂,x). Other conventions are possible, but their formulas must change consistently.
04
2D Fenwick Tree
The same idea, extended to a grid.
What changes?
Instead of an array, imagine a matrix with rows and columns. A 2D BIT stores partial sums over rectangular regions aligned with its index structure. Updating one cell and querying a rectangle both take logarithmic time in each dimension.
rectangle = P(x₂,y₂) − P(x₁−1,y₂)
− P(x₂,y₁−1) + P(x₁−1,y₁−1)
P(x, y) is the sum of the rectangle from the top-left corner through (x, y).
Visualise a prefix rectangle
Green cells illustrate a top-left prefix region.
Point updateWalk through affected Fenwick indices in the row dimension and, inside each, the column dimension.
Prefix queryAccumulate the relevant 2D tree entries while moving down through both index dimensions.
Rectangle queryUse inclusion–exclusion on four prefix rectangles to keep only the requested rectangle.
Typical uses: dynamic grid sums, image-like matrices, board simulations, and counting points inside axis-aligned rectangles. A basic 2D BIT supports point updates and rectangle-sum queries; range updates in two dimensions require a more elaborate construction.