Python 3.11+
The examples use standard Python containers and syntax available in the supported browser runtime; Fenwick Tree itself is taught as an interview abstraction.
Verify in Python docs(opens in a new tab)Compact indexed tree supporting logarithmic prefix aggregates and point updates. This guide turns that contract into deliberate Python operations, interview invariants, and a runnable practice loop.
Recognize it when
Consider Fenwick Tree when the prompt's constraints and required operations match this shape: Compact indexed tree supporting logarithmic prefix aggregates and point updates.

Sign in to save your code and progress across devices. The lesson and problem statement remain public.
Fenwick trees use a one-based array. Slot i owns the suffix block ending at i whose length is i & -i. For example, slot 6 owns positions 5 through 6, while slot 8 owns positions 1 through 8. These overlapping blocks let a prefix decompose into only O(log n) pieces.
def fenwick_block_ranges(n):
return [[index - (index & -index) + 1, index] for index in range(1, n + 1)]Implement fenwick_block_ranges(n). Return [left, right] one-based inclusive ranges owned by Fenwick slots 1 through n.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
lowbit = i & -i encodes both directions. A prefix query subtracts lowbit to remove the block it just consumed. A point update adds lowbit to visit every larger block containing that position. Keep public indexes zero-based if the prompt uses them, but convert once at the boundary.
A range sum [left, right] is prefix(right) - prefix(left - 1). The left - 1 boundary is essential; prefix(-1) should contribute zero. Each query or update changes one bit per step, so it takes O(log n).
def fenwick_tree_trace(values, operations):
tree = [0] * (len(values) + 1)
def add(index, delta):
index += 1
while index < len(tree):
tree[index] += delta
index += index & -index
def prefix(index):
index += 1
total = 0
while index > 0:
total += tree[index]
index -= index & -index
return total
for index, value in enumerate(values):
add(index, value)
results = []
for operation in operations:
if operation[0] == "prefix":
results.append(prefix(operation[1]))
elif operation[0] == "add":
add(operation[1], operation[2])
elif operation[0] == "range":
results.append(prefix(operation[2]) - prefix(operation[1] - 1))
return resultsImplement fenwick_tree_trace(values, operations). Operations are ["prefix", index], ["add", index, delta], or ["range", left, right], with inclusive indexes. Return one number for each prefix or range query and do not mutate values.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
Choose Fenwick for point updates plus prefix-friendly invertible aggregates such as sums: it is compact and short to implement. Choose a segment tree for arbitrary associative range combines, explicit interval ownership, or extensions such as lazy propagation. If there are no updates, precomputed prefix sums are simpler.
Say: “Tree slot i stores the aggregate for the block ending at i with length lowbit(i). Queries remove owned blocks; updates climb to every owner.” Trace one prefix in binary, then state O(log n) per operation and O(n) space. See the Python list reference(opens in a new tab) for the underlying array behavior.
Python 3.11+
The examples use standard Python containers and syntax available in the supported browser runtime; Fenwick Tree itself is taught as an interview abstraction.
Verify in Python docs(opens in a new tab)Interview bounds depend on the stated representation, input model, and real Python operations.
| Operation | Average | Worst | Interview note |
|---|---|---|---|
| Core Fenwick Tree workflow | O((n + m) log n) | O((n + m) log n) | Build one-indexed Fenwick aggregates, move by low bits for updates and prefix queries, and subtract prefix boundaries for ranges. |
O(n) for the demonstrated Fenwick Tree workflow.
These are the mistakes most likely to survive a happy-path example and fail a boundary case.
Placeholder code cannot preserve the Fenwick Tree invariant or satisfy the public contract.
Prevent it: Implement the smallest complete transition and run the public tests before adding optimizations.
Avoid
def fenwick_tree_trace(values, operations):
passUse instead
def fenwick_tree_trace(values, operations):
tree = [0] * (len(values) + 1)
def add(index, delta):
index += 1
while index < len(tree):
tree[index] += delta
index += index & -index
def prefix(index):
index += 1
total = 0
while index > 0:
total += tree[index]
index -= index & -index
return total
for index, value in enumerate(values):
add(index, value)
results = []
for operation in operations:
if operation[0] == "prefix":
results.append(prefix(operation[1]))
elif operation[0] == "add":
add(operation[1], operation[2])
elif operation[0] == "range":
results.append(prefix(operation[2]) - prefix(operation[1] - 1))
return resultsWhere you will hit this: Trace Fenwick-Tree Prefixes(opens in a new tab)
Uses prefix(left) instead of prefix(left - 1), incorrectly excluding the first value in every range.
Prevent it: Keep this invariant visible while editing: State the precise Fenwick Tree invariant before coding and preserve it after every update, traversal step, or recursive return.
Avoid
def fenwick_tree_trace(values, operations):
results = []
for operation in operations:
if operation[0] == "range":
results.append(sum(values[operation[1] + 1:operation[2] + 1]))
elif operation[0] == "prefix":
results.append(sum(values[:operation[1] + 1]))
return resultsUse instead
def fenwick_tree_trace(values, operations):
tree = [0] * (len(values) + 1)
def add(index, delta):
index += 1
while index < len(tree):
tree[index] += delta
index += index & -index
def prefix(index):
index += 1
total = 0
while index > 0:
total += tree[index]
index -= index & -index
return total
for index, value in enumerate(values):
add(index, value)
results = []
for operation in operations:
if operation[0] == "prefix":
results.append(prefix(operation[1]))
elif operation[0] == "add":
add(operation[1], operation[2])
elif operation[0] == "range":
results.append(prefix(operation[2]) - prefix(operation[1] - 1))
return resultsWhere you will hit this: Trace Fenwick-Tree Prefixes(opens in a new tab)
Handle empty state, duplicate values, aliasing, and serialization boundaries explicitly in tests.
Prevent it: Account for every slice, copy, sort, membership test, and container mutation before claiming O((n + m) log n).
Avoid
def fenwick_tree_trace(values, operations):
results = []
for operation in operations:
if operation[0] == "range":
results.append(sum(values[operation[1] + 1:operation[2] + 1]))
elif operation[0] == "prefix":
results.append(sum(values[:operation[1] + 1]))
return resultsUse instead
def fenwick_tree_trace(values, operations):
tree = [0] * (len(values) + 1)
def add(index, delta):
index += 1
while index < len(tree):
tree[index] += delta
index += index & -index
def prefix(index):
index += 1
total = 0
while index > 0:
total += tree[index]
index -= index & -index
return total
for index, value in enumerate(values):
add(index, value)
results = []
for operation in operations:
if operation[0] == "prefix":
results.append(prefix(operation[1]))
elif operation[0] == "add":
add(operation[1], operation[2])
elif operation[0] == "range":
results.append(prefix(operation[2]) - prefix(operation[1] - 1))
return resultsWhere you will hit this: Map Sum Pairs(opens in a new tab)
Official Python documentation supports language behavior. Canonical problem pages provide additional practice context.
python-docs · checked 2026-07-27