PrepStack · Markdown HTML

Fenwick tree

Range-query data structures · HTML

Formal shape

Support add(i,delta) and prefix(r)=aggregate(a[0:r]); derive a range by canceling two prefixes.

Recognition signals

False friends

SignalWhy it is different
Complex range assignmentA basic Fenwick tree is unnatural here; consider a lazy segment tree.
Non-invertible dynamic aggregateDynamic range minimum cannot be canceled from two prefixes; use a segment tree.

Core invariant

In 1-based indexing, tree[i] stores the aggregate on (i-lowbit(i),i]; a query chain partitions a prefix into disjoint blocks.

State, transition, and processing order

ItemDefinition
StateAn n+1 tree array; the public API is 0-based and shifts indices on entry.
Transitionadd climbs with i+=lowbit(i); prefix collects blocks while i-=lowbit(i).
Frontier / orderAn update moves toward larger ancestor blocks; a query repeatedly clears its lowest set bit to reach zero.

Python skeleton

class Fenwick:
    def __init__(self, n):
        self.n = n
        self.t = [0] * (n + 1)
    def add(self, index, delta):
        i = index + 1
        while i <= self.n:
            self.t[i] += delta
            i += i & -i
    def prefix(self, right):
        total, i = 0, right
        while i:
            total += self.t[i]
            i -= i & -i
        return total
    def range_sum(self, left, right):
        return self.prefix(right) - self.prefix(left)

Correctness sketch

  1. lowbit uniquely determines every stored block.
  2. The add chain reaches exactly the blocks containing the changed position.
  3. The prefix descent covers the requested prefix with disjoint blocks.
  4. Canceling two prefixes leaves exactly [left,right).

Complexity

TimeSpaceParameters
O(log n) per update, prefix, or range sumO(n)n array positions; repeated-add construction costs O(n log n)

Edge cases

Error patterns

PatternWhy it fails / fix
Updating internal index zerolowbit(0)=0 causes an infinite loop.
Endpoint driftFix prefix(r) as [0,r) everywhere.
Treating set as addAssigning x requires delta=x-old.

Selection and exclusion rules

RelationTemplateBoundary
offline alternativeMerge-sort cross-half countingOnly one relational count is needed
general alternativeSegment tree range aggregationThe summary cannot be expressed through invertible prefixes

Original micro-example

PartDetail
ResultThe new range sum is 8.
ScenarioFor [2,0,3,1], add 4 at index 1 and query [1,4).
Walkthroughadd changes every block containing the second item; prefix(4)-prefix(1)=10-2.

Recall prompts

My notes