Chapter 3.10: Fenwick Tree (Binary Indexed Tree)
๐ Before You Continue: You should already know prefix sums (Chapter 3.2) and bitwise operations. This chapter complements Segment Tree (Chapter 3.9) โ BIT code is shorter, with smaller constants, but supports fewer operations.
Fenwick Tree (also known as Binary Indexed Tree / BIT) is one of the most commonly used data structures in competitive programming: under 15 lines of code, yet supports point updates and prefix queries in O(log N) time.
3.10.1 The Core Idea: What Is lowbit?
Bitwise Principle of lowbit
For any positive integer x, lowbit(x) = x & (-x) returns the value of the lowest set bit in the binary representation of x.
x = 6 โ binary: 0110
-x = -6 โ two's complement: 1010 (bitwise NOT + 1)
x & (-x) = 0010 = 2 โ lowest set bit corresponds to 2^1 = 2
Examples:
| x | Binary | -x (two's complement) | x & (-x) | Meaning |
|---|---|---|---|---|
| 1 | 0001 | 1111 | 0001 = 1 | Manages 1 element |
| 2 | 0010 | 1110 | 0010 = 2 | Manages 2 elements |
| 3 | 0011 | 1101 | 0001 = 1 | Manages 1 element |
| 4 | 0100 | 1100 | 0100 = 4 | Manages 4 elements |
| 6 | 0110 | 1010 | 0010 = 2 | Manages 2 elements |
| 8 | 1000 | 1000 | 1000 = 8 | Manages 8 elements |
BIT Tree Index Intuition
The elegance of BIT: tree[i] does not store a single element, but stores the sum of a range, with length exactly lowbit(i).
BIT ๆ ๅฝข็ปๆ็คบๆ๏ผn=8๏ผ๏ผ
flowchart BT
T1["tree[1]\nA[1]\n็ฎก็ 1 ไธช"]
T2["tree[2]\nA[1..2]\n็ฎก็ 2 ไธช"]
T3["tree[3]\nA[3]\n็ฎก็ 1 ไธช"]
T4["tree[4]\nA[1..4]\n็ฎก็ 4 ไธช"]
T5["tree[5]\nA[5]\n็ฎก็ 1 ไธช"]
T6["tree[6]\nA[5..6]\n็ฎก็ 2 ไธช"]
T7["tree[7]\nA[7]\n็ฎก็ 1 ไธช"]
T8["tree[8]\nA[1..8]\n็ฎก็ 8 ไธช"]
T1 --> T2
T3 --> T4
T2 --> T4
T5 --> T6
T7 --> T8
T6 --> T8
T4 --> T8
style T8 fill:#dbeafe,stroke:#3b82f6
style T4 fill:#e0f2fe,stroke:#0284c7
style T2 fill:#f0f9ff,stroke:#38bdf8
style T6 fill:#f0f9ff,stroke:#38bdf8
ๆฅ่ฏข prefix(7) ็่ทณ่ฝฌ่ทฏๅพ๏ผ
flowchart LR
Q7["i=7\nๅ tree[7]=A[7]"] -->|"7-lowbit(7)=6"| Q6
Q6["i=6\nๅ tree[6]=A[5..6]"] -->|"6-lowbit(6)=4"| Q4
Q4["i=4\nๅ tree[4]=A[1..4]"] -->|"4-lowbit(4)=0"| Q0
Q0(["i=0 ๅๆญข\nๅ
ฑ 3 ๆญฅ = O(log 7)"])
style Q0 fill:#dcfce7,stroke:#16a34a
๐ก ่ทณ่ฝฌ่งๅพ๏ผ ๆฅ่ฏขๆถ
i -= lowbit(i)๏ผๅไธ่ทณ๏ผ๏ผๆดๆฐๆถi += lowbit(i)๏ผๅไธ่ทณ๏ผใๆฏๆฌก่ทณ่ฝฌๆถ้คๆไฝไฝ็ 1๏ผๆๅค log N ๆญฅใ
Index i: 1 2 3 4 5 6 7 8
Range managed by tree[i]:
tree[1] = A[1] (length lowbit(1)=1)
tree[2] = A[1]+A[2] (length lowbit(2)=2)
tree[3] = A[3] (length lowbit(3)=1)
tree[4] = A[1]+...+A[4] (length lowbit(4)=4)
tree[5] = A[5] (length lowbit(5)=1)
tree[6] = A[5]+A[6] (length lowbit(6)=2)
tree[7] = A[7] (length lowbit(7)=1)
tree[8] = A[1]+...+A[8] (length lowbit(8)=8)
ๆดๆฐไฝ็ฝฎ 3 ็่ทณ่ฝฌ่ทฏๅพ๏ผ
flowchart LR
U3["i=3\nๆดๆฐ tree[3]"] -->|"3+lowbit(3)=4"| U4
U4["i=4\nๆดๆฐ tree[4]"] -->|"4+lowbit(4)=8"| U8
U8["i=8\nๆดๆฐ tree[8]"] -->|"8+lowbit(8)=16>n"| U_end
U_end(["i>n ๅๆญข\nๅ
ฑ 3 ๆญฅ = O(log N)"])
style U_end fill:#dcfce7,stroke:#16a34a
When querying prefix sum prefix(7), jump up via i -= lowbit(i):
i=7: addtree[7](manages A[7]), then7 - lowbit(7) = 7 - 1 = 6i=6: addtree[6](manages A[5..6]), then6 - lowbit(6) = 6 - 2 = 4i=4: addtree[4](manages A[1..4]), then4 - lowbit(4) = 4 - 4 = 0, stop
Total 3 steps = O(log 7) โ 3 steps.
When updating position 3, jump up via i += lowbit(i):
i=3: updatetree[3], then3 + lowbit(3) = 3 + 1 = 4i=4: updatetree[4], then4 + lowbit(4) = 4 + 4 = 8i=8: updatetree[8], 8 > n, stop
3.10.2 Point Update + Prefix Query โ Complete Code
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Fenwick Tree (Binary Indexed Tree) โ Classic Implementation
// Supports: Point Update O(log N), Prefix Sum Query O(log N)
// Arrays are 1-INDEXED (critical!)
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 300005;
int n;
long long tree[MAXN]; // BIT array, 1-indexed
// โโ lowbit: returns the value of the lowest set bit โโ
// x & (-x) works because:
// -x in two's complement = ~x + 1
// The lowest set bit of x is preserved, all higher bits cancel out
// Example: x=6 (0110), -x=1010, x&(-x)=0010=2
inline int lowbit(int x) {
return x & (-x);
}
// โโ update: add val to position i โโ
// Walk UP the tree: i += lowbit(i)
// Each ancestor that covers position i gets updated
void update(int i, long long val) {
for (; i <= n; i += lowbit(i))
tree[i] += val;
// Time: O(log N) โ at most log2(N) iterations
}
// โโ query: return prefix sum A[1..i] โโ
// Walk DOWN the tree: i -= lowbit(i)
// Decompose [1..i] into O(log N) non-overlapping ranges
long long query(int i) {
long long sum = 0;
for (; i > 0; i -= lowbit(i))
sum += tree[i];
return sum;
// Time: O(log N) โ at most log2(N) iterations
}
// โโ build: initialize BIT from an existing array A[1..n] โโ
// Method 1: N individual updates โ O(N log N)
void build_slow(long long A[]) {
fill(tree + 1, tree + n + 1, 0LL);
for (int i = 1; i <= n; i++)
update(i, A[i]);
}
// Method 2: O(N) build using the "direct parent" trick
void build_fast(long long A[]) {
for (int i = 1; i <= n; i++) {
tree[i] += A[i];
int parent = i + lowbit(i); // direct parent in BIT
if (parent <= n)
tree[parent] += tree[i];
}
}
// โโ Full Example โโ
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int q;
cin >> n >> q;
long long A[MAXN] = {};
for (int i = 1; i <= n; i++) cin >> A[i];
build_fast(A); // O(N) initialization
while (q--) {
int type;
cin >> type;
if (type == 1) {
// Point update: A[i] += val
int i; long long val;
cin >> i >> val;
update(i, val);
} else {
// Prefix query: sum of A[1..r]
int r;
cin >> r;
cout << query(r) << "\n";
}
}
return 0;
}
3.10.3 Range Query = prefix(r) - prefix(l-1)
Range query sum(l, r) is identical to the prefix sum technique:
// Range sum query: sum of A[l..r]
// Time: O(log N) โ two prefix queries
long long range_query(int l, int r) {
return query(r) - query(l - 1);
// query(r) = A[1] + A[2] + ... + A[r]
// query(l-1) = A[1] + A[2] + ... + A[l-1]
// difference = A[l] + A[l+1] + ... + A[r]
}
// Example usage:
// A = [3, 1, 4, 1, 5, 9, 2, 6] (1-indexed)
// range_query(3, 6) = query(6) - query(2)
// = (3+1+4+1+5+9) - (3+1)
// = 23 - 4 = 19
// Verify: A[3]+A[4]+A[5]+A[6] = 4+1+5+9 = 19 โ
3.10.4 Comparison: Prefix Sum vs BIT vs Segment Tree
| Operation | Prefix Sum Array | Fenwick Tree (BIT) | Segment Tree |
|---|---|---|---|
| Build | O(N) | O(N) or O(N log N) | O(N) |
| Prefix Query | O(1) | O(log N) | O(log N) |
| Range Query | O(1) | O(log N) | O(log N) |
| Point Update | O(N) rebuild | O(log N) โ | O(log N) โ |
| Range Update | O(N) | O(log N) (Difference BIT) | O(log N) (lazy tag) |
| Range Min/Max | O(1) (sparse table) | โ Not supported | โ Supported |
| Code Complexity | Minimal | Simple (10 lines) | Complex (50+ lines) |
| Constant Factor | Smallest | Very small | Larger |
| Space | O(N) | O(N) | O(4N) |
When to choose BIT?
- โ Only need prefix/range sum + point update
- โ Need extremely concise code (fewer bugs in contest)
- โ Counting inversions, merge sort counting problems
- โ Need range min/max โ use Segment Tree
- โ Need complex range operations (range multiply, etc.) โ use Segment Tree
3.10.5 Interactive Visualization: BIT Update Process
3.10.6 Range Update + Point Query (Difference BIT)
Standard BIT supports "point update + prefix query". Using the difference array technique, it can instead support "range update + point query".
Principle
Let difference array D[i] = A[i] - A[i-1] (D[1] = A[1]), then:
A[i] = D[1] + D[2] + ... + D[i](i.e., A[i] is the prefix sum of D)- Adding val to all A[l..r] is equivalent to:
D[l] += val; D[r+1] -= val
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Difference BIT: Range Update + Point Query
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 300005;
int n;
long long diff_bit[MAXN]; // BIT over difference array D[]
inline int lowbit(int x) { return x & (-x); }
// Update D[i] += val in the difference BIT
void diff_update(int i, long long val) {
for (; i <= n; i += lowbit(i))
diff_bit[i] += val;
}
// Query A[i] = sum of D[1..i] = prefix query on diff BIT
long long diff_query(int i) {
long long s = 0;
for (; i > 0; i -= lowbit(i))
s += diff_bit[i];
return s;
}
// Range update: add val to all A[l..r]
// Equivalent to: D[l] += val, D[r+1] -= val
void range_update(int l, int r, long long val) {
diff_update(l, val); // D[l] += val
diff_update(r + 1, -val); // D[r+1] -= val
}
// Point query: return current value of A[i]
// A[i] = D[1] + D[2] + ... + D[i] = prefix_sum(D, i)
long long point_query(int i) {
return diff_query(i);
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int q;
cin >> n >> q;
// Initialize: read A[i], build diff BIT
for (int i = 1; i <= n; i++) {
long long x; cin >> x;
// D[i] = A[i] - A[i-1]: use two updates
diff_update(i, x);
if (i + 1 <= n) diff_update(i + 1, -x); // will be overridden by next iteration
// Simpler: just set D[i] = A[i]-A[i-1] directly
}
// Better initialization using range_update for each element:
// fill diff_bit with 0, then range_update(i, i, A[i]) for each i
// Or: diff_update(1, A[1]); for i>=2: diff_update(i, A[i]-A[i-1])
while (q--) {
int type; cin >> type;
if (type == 1) {
int l, r; long long val;
cin >> l >> r >> val;
range_update(l, r, val); // A[l..r] += val, O(log N)
} else {
int i; cin >> i;
cout << point_query(i) << "\n"; // query A[i], O(log N)
}
}
return 0;
}
Advanced: Range Update + Range Query (Dual BIT)
To support both range update + range query simultaneously, use two BITs:
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Double BIT: Range Update + Range Query
// Formula: sum(1..r) = B1[r] * r - B2[r]
// where B1 is BIT over D[], B2 is BIT over (i-1)*D[i]
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
long long B1[MAXN], B2[MAXN]; // Two BITs
inline int lowbit(int x) { return x & (-x); }
void add(long long* b, int i, long long v) {
for (; i <= n; i += lowbit(i)) b[i] += v;
}
long long sum(long long* b, int i) {
long long s = 0;
for (; i > 0; i -= lowbit(i)) s += b[i];
return s;
}
// Range update: add val to A[l..r]
void range_add(int l, int r, long long val) {
add(B1, l, val);
add(B1, r + 1, -val);
add(B2, l, val * (l - 1)); // compensate for prefix formula
add(B2, r + 1, -val * r);
}
// Prefix sum A[1..r]
long long prefix_sum(int r) {
return sum(B1, r) * r - sum(B2, r);
}
// Range sum A[l..r]
long long range_sum(int l, int r) {
return prefix_sum(r) - prefix_sum(l - 1);
}
3.10.7 USACO-Style Problem: Counting Inversions with BIT
Problem Statement
Counting Inversions (O(N log N))
Given an integer array A of length N (distinct elements, range 1..N), count the number of inversions.
Inversion: a pair of indices (i, j) where i < j but A[i] > A[j].
Constraints: N โค 3ร10โต, requires O(N log N) solution.
Sample Input:
5
3 1 4 2 5
Sample Output:
3
Explanation: Inversions are (3,1), (3,2), (4,2), total 3 pairs.
Solution: BIT Inversion Count
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Counting Inversions using Fenwick Tree โ O(N log N)
//
// Key Idea:
// Process A[i] from left to right.
// For each A[i], the number of inversions with A[i] as the
// RIGHT element = count of already-processed values > A[i]
// = (elements processed so far) - (elements <= A[i])
// = i-1 - prefix_query(A[i])
// Sum over all i gives total inversions.
//
// BIT role: track frequency of seen values.
// After seeing value v: update(v, +1)
// Query # of values <= x: query(x)
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 300005;
int n;
int bit[MAXN]; // BIT for frequency counting; bit[v] tracks how many times v appeared
inline int lowbit(int x) { return x & (-x); }
// Add 1 to position v (we saw value v)
void update(int v) {
for (; v <= n; v += lowbit(v))
bit[v]++;
}
// Count how many values in [1..v] have been seen
int query(int v) {
int cnt = 0;
for (; v > 0; v -= lowbit(v))
cnt += bit[v];
return cnt;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
ll inversions = 0;
for (int i = 1; i <= n; i++) {
int a;
cin >> a;
// Count inversions where a is the RIGHT element:
// # of already-seen values GREATER than a
// = (i-1 elements seen so far) - (# of seen values <= a)
int less_or_equal = query(a); // # of seen values in [1..a]
int greater = (i - 1) - less_or_equal; // # of seen values in [a+1..n]
inversions += greater;
// Mark that we've now seen value a
update(a);
}
cout << inversions << "\n";
return 0;
}
/*
Trace for A = [3, 1, 4, 2, 5]:
i=1, a=3: seen=[], query(3)=0, greater=0-0=0. inversions=0. update(3).
i=2, a=1: seen=[3], query(1)=0, greater=1-0=1. inversions=1. update(1).
(3 > 1: that's 1 inversion: (3,1) โ)
i=3, a=4: seen=[3,1], query(4)=2, greater=2-2=0. inversions=1. update(4).
(no element > 4 was seen before)
i=4, a=2: seen=[3,1,4], query(2)=1, greater=3-1=2. inversions=3. update(2).
(3>2 and 4>2: 2 inversions: (3,2),(4,2) โ)
i=5, a=5: seen=[3,1,4,2], query(5)=4, greater=4-4=0. inversions=3. update(5).
Final: 3 โ
*/
Complexity Analysis:
- Time: O(N log N) โ N iterations, each O(log N) for update + query
- Space: O(N) for BIT
Extension: If array elements are not in range 1..N, first apply coordinate compression before using BIT:
// Coordinate compression for arbitrary values
vector<int> A(n);
for (int i = 0; i < n; i++) cin >> A[i];
// Step 1: sort and deduplicate
vector<int> sorted_A = A;
sort(sorted_A.begin(), sorted_A.end());
sorted_A.erase(unique(sorted_A.begin(), sorted_A.end()), sorted_A.end());
// Step 2: replace each value with its rank (1-indexed)
for (int i = 0; i < n; i++) {
A[i] = lower_bound(sorted_A.begin(), sorted_A.end(), A[i]) - sorted_A.begin() + 1;
// A[i] is now in [1..M] where M = sorted_A.size()
}
// Now use BIT with n = sorted_A.size()
3.10.8 Common Mistakes
โ Mistake 1: Wrong lowbit Implementation
// โ WRONG โ common typo/confusion
int lowbit(int x) { return x & (x - 1); } // This CLEARS the lowest bit, not returns it!
// x=6 (0110): x&(x-1) = 0110&0101 = 0100 = 4 (WRONG, should be 2)
int lowbit(int x) { return x % 2; } // Only works for last bit, not lowbit value
// โ
CORRECT
int lowbit(int x) { return x & (-x); }
// x=6: -6 = ...11111010 (two's complement)
// 0110 & 11111010 = 0010 = 2 โ
Memory trick: x & (-x) reads as "x AND negative-x". -x is bitwise NOT plus 1, which clears all bits below the lowest set bit, flips all bits above it, and the AND operation keeps only the lowest set bit.
โ Mistake 2: 0-indexed Array (the 0-index trap)
BIT must use 1-indexed arrays. 0-indexed causes infinite loops!
// โ WRONG โ 0-indexed causes infinite loop!
// If i = 0: query loop: i -= lowbit(0) = 0 - (0 & 0) = 0 - 0 = 0 โ infinite loop!
// (Actually lowbit(0) = 0 & 0 = 0, so i never decreases)
void query_WRONG(int i) { // i is 0-indexed
int s = 0;
for (; i > 0; i -= lowbit(i)) // if i=0 initially, loop doesn't execute but
s += bit[i]; // if called with i=0 during calculation... disaster
return s;
}
// โ WRONG โ forgetting +1 when converting to 1-indexed
int arr[n]; // 0-indexed A[0..n-1]
for (int i = 0; i < n; i++) {
update(i, arr[i]); // BUG: should be update(i+1, arr[i])
}
// โ
CORRECT โ always shift to 1-indexed
for (int i = 0; i < n; i++) {
update(i + 1, arr[i]); // convert 0-indexed i to 1-indexed i+1
}
// And remember: query(r+1) - query(l) for 0-indexed range [l, r]
โ Mistake 3: Integer Overflow in Large Sum
// โ WRONG โ tree[] should be long long for large sums
int tree[MAXN]; // overflow if sum > 2^31
// โ
CORRECT
long long tree[MAXN];
// Also: when counting inversions, inversions can be up to N*(N-1)/2 โ 4.5ร10^10 for N=3ร10^5
// Always use long long for the result counter!
long long inversions = 0; // โ
not int!
โ Mistake 4: Forgetting to Clear BIT Between Test Cases
// โ WRONG โ in problems with multiple test cases
int T; cin >> T;
while (T--) {
// forgot to clear tree[]!
// Old data from previous test case corrupts results
solve();
}
// โ
CORRECT โ reset before each test case
int T; cin >> T;
while (T--) {
fill(tree + 1, tree + n + 1, 0LL); // clear BIT
solve();
}
3.10.9 Chapter Summary
๐ Formula Quick Reference
| Operation | Code | Description |
|---|---|---|
| lowbit | x & (-x) | Value of lowest set bit of x |
| Point Update | for(;i<=n;i+=lowbit(i)) t[i]+=v | Propagate upward |
| Prefix Query | for(;i>0;i-=lowbit(i)) s+=t[i] | Decompose downward |
| Range Query | query(r) - query(l-1) | Difference formula |
| Range Update (Diff BIT) | upd(l,+v); upd(r+1,-v) | Difference array |
| Inversion Count | (i-1) - query(a[i]) | Count when processing each element |
| Array must be | 1-indexed | 0-indexed โ infinite loop |
โ FAQ
Q1: Both BIT and Segment Tree support prefix sum + point update. Which should I choose?
A: Use BIT whenever possible. BIT code is only 10 lines, has smaller constants (empirically 2-3x faster), and lower error probability. Only choose Segment Tree when you need range min/max (RMQ), range coloring, or more complex range operations. In contests, BIT is the "default weapon", Segment Tree is "heavy artillery".
Q2: Can BIT support Range Minimum Query (RMQ)?
A: Standard BIT cannot support RMQ, because the min operation has no "inverse" (cannot "undo" a merged min value like subtraction). For range min/max, use Segment Tree or Sparse Table. There is a "static BIT for RMQ" technique, but it only works without updates and has limited practical use.
Q3: Can BIT support 2D (2D BIT)?
A: Yes! 2D BIT solves 2D prefix sum + point update problems, with complexity O(log N ร log M). The code structure uses two nested loops:
// 2D BIT update void update2D(int x, int y, long long v) { for (int i = x; i <= N; i += lowbit(i)) for (int j = y; j <= M; j += lowbit(j)) bit[i][j] += v; }Less common in USACO, but occasionally needed for 2D coordinate counting problems.
3.10.10 Practice Problems
Given an array of length N, support two operations:
1 i x: Increase A[i] by x2 l r: Query A[l] + A[l+1] + ... + A[r]
Constraints: N, Q โค 10โต.
Hint: Direct BIT application. Use update(i, x) and query(r) - query(l-1).
Given N operations, each either inserts an integer (range 1..10โถ) or queries "how many of the currently inserted integers are โค K?"
Hint: BIT maintains a frequency array over the value domain. update(v, 1) inserts value v, query(K) is the answer.
Given an array of length N (initially all zeros), support two operations:
1 l r x: Add x to every element in A[l..r]2 i: Query the current value of A[i]
Constraints: N, Q โค 3ร10โต.
Hint: Use Difference BIT (Section 3.10.6).
Given an array of length N with elements in range 1..10โน (possibly repeated). Count the number of inversions.
Constraints: N โค 3ร10โต.
Hint: First apply coordinate compression, then use BIT counting (variant of Section 3.10.7). Note equal elements: (i,j) with i<j and A[i]>A[j] (strictly greater) counts as an inversion.
Given an array of length N, support two operations:
1 l r x: Add x to every element in A[l..r]2 l r: Query A[l] + ... + A[r]
Constraints: N, Q โค 3ร10โต, elements and x can reach 10โน.
Hint: Use Dual BIT (Dual BIT method at end of Section 3.10.6). Formula: prefix_sum(r) = B1[r] * r - B2[r], where B1 maintains the difference array and B2 maintains the weighted difference array. Derivation: let D[i] be the difference array, then A[1]+...+A[r] = ฮฃแตขโโสณ ฮฃโฑผโโโฑ D[j] = ฮฃโฑผโโสณ D[j]*(r-j+1) = (r+1)ฮฃ D[j] - ฮฃ jD[j].
๐ก Chapter Connection: BIT and Segment Tree are the two most commonly paired data structures in USACO. BIT handles 80% of scenarios with 1/5 the code of Segment Tree. After mastering BIT, return to Chapter 3.9 to learn Segment Tree lazy propagationโthe territory BIT cannot reach.