Build: P[0]=0, P[i] = P[i-1] + arr[i-1]. One pass, O(n).
Query: sum(l, r) = P[r+1] - P[l]. Single subtraction, O(1).
2D extension: same principle on matrices for rectangle sum queries.
Trade-off: O(n) extra space and no efficient updates. Fenwick Tree handles updates in O(log n).
Analytics dashboards with millions of range queries per hour use prefix sums to avoid O(n) per query.
Off-by-one on the P[0]=0 sentinel is the #1 source of wrong answers.
Using prefix sums on arrays that change frequently. Every update requires an O(n) rebuild. Use Fenwick Tree or Segment Tree for dynamic data.
Plain-English First
Imagine you're a cashier and someone asks 'how much did customers spend between 3pm and 7pm?' You could add up every receipt from that window — or you could keep a running total on a notepad all day and just subtract two numbers. That notepad IS a prefix sum array. You do a bit of extra work upfront so that every future question costs almost nothing to answer.
Range sum queries — 'what is the sum of elements between index L and index R?' — appear everywhere: analytics dashboards aggregating revenue by time window, genomics pipelines counting nucleotide frequencies in chromosome segments, image processing computing integral images for feature detection. The naive approach loops over the range each time: O(n) per query. At millions of queries, this is a bottleneck.
Prefix sums eliminate the per-query loop. A one-time O(n) preprocessing pass builds a cumulative sum array. Every subsequent range query becomes a single subtraction: P[r+1] - P[l]. The trade-off is O(n) extra space and O(n) rebuild cost on updates — which makes prefix sums ideal for static or read-heavy datasets and unsuitable for frequently-updated arrays.
Two extensions multiply the technique's power: 2D prefix sums enable O(1) rectangle sum queries on matrices (the basis of integral images in computer vision), and difference arrays invert the pattern to support O(1) range updates with a single final read. For dynamic data requiring both queries and updates, Fenwick Trees and Segment Trees provide O(log n) for both operations at the cost of implementation complexity.
What is Prefix Sum Array? — Plain English
A Prefix Sum Array (also called a cumulative sum array) transforms an array so that range sum queries can be answered in O(1) after O(n) preprocessing. Without it, summing any subarray takes O(n). With it, any range sum takes O(1).
The prefix array P is defined as P[i] = arr[0] + arr[1] + ... + arr[i-1]. Then sum(arr[l..r]) = P[r+1] - P[l]. This works because P[r+1] includes everything up to index r, and P[l] includes everything before index l — the difference is exactly the range.
io/thecodeforge/algo/PrefixSumArray.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package io.thecodeforge.algo;
import java.util.Arrays;
publicclassPrefixSumArray {
privatefinallong[] prefix;
/**
* Builds the prefix sum array in O(n).
* Useslong to prevent integer overflow on large sums.
*/
publicPrefixSumArray(int[] arr) {
prefix = newlong[arr.length + 1];
for (int i = 0; i < arr.length; i++) {
prefix[i + 1] = prefix[i] + arr[i];
}
}
/**
* Returns the sum of arr[l..r] inclusive. O(1).
* @throwsIllegalArgumentExceptionif l > r or indices out of bounds
*/
publiclongrangeSum(int l, int r) {
if (l < 0 || r >= prefix.length - 1 || l > r) {
thrownewIllegalArgumentException(
String.format("Invalid range [%d, %d] for array of length %d", l, r, prefix.length - 1)
);
}
return prefix[r + 1] - prefix[l];
}
/**
* Returns the total sum of the entire array. O(1).
*/
publiclongtotalSum() {
return prefix[prefix.length - 1] - prefix[0];
}
publicstaticvoidmain(String[] args) {
int[] arr = {3, 1, 4, 1, 5, 9, 2, 6};
PrefixSumArray ps = newPrefixSumArray(arr);
System.out.println("Array: " + Arrays.toString(arr));
System.out.println("Prefix: " + Arrays.toString(ps.prefix));
System.out.println("sum(2..5) = " + ps.rangeSum(2, 5)); // 4+1+5+9 = 19System.out.println("sum(0..7) = " + ps.rangeSum(0, 7)); // 31System.out.println("sum(0..0) = " + ps.rangeSum(0, 0)); // 3System.out.println("sum(7..7) = " + ps.rangeSum(7, 7)); // 6
}
}
Output
Array: [3, 1, 4, 1, 5, 9, 2, 6]
Prefix: [0, 3, 4, 8, 9, 14, 23, 25, 31]
sum(2..5) = 19
sum(0..7) = 31
sum(0..0) = 3
sum(7..7) = 6
Why Subtraction Gives You the Range Sum
P[r+1] = sum of arr[0..r]. Everything up to and including r.
P[0]=0 is the sentinel. Without it, l=0 requires a special case.
The formula is always P[r+1] - P[l]. Never P[r] - P[l]. The +1 is critical.
Production Insight
A genomics pipeline counted nucleotide frequencies in sliding 1000-base windows across a 3-billion-base chromosome. With 3 million windows and a naive O(n) loop per window, total operations were 3 million x 1000 = 3 billion. Using prefix sums: 3 million x 1 subtraction = 3 million operations. The pipeline runtime dropped from 45 minutes to 8 seconds. The prefix sum build cost (3 billion additions) was amortized across 3 million queries.
Key Takeaway
Prefix sums trade O(n) preprocessing and O(n) extra space for O(1) range queries. The formula is always P[r+1] - P[l]. The P[0]=0 sentinel eliminates special cases. Use long for the prefix array to prevent overflow on large sums.
How Prefix Sum Array Works — Step by Step
Build (O(n)): 1. Allocate prefix array P of size n+1. Set P[0] = 0. 2. For i from 1 to n: P[i] = P[i-1] + arr[i-1].
Range sum query (O(1)): 3. sum(arr[l..r]) = P[r+1] - P[l] (0-indexed).
2D prefix sum (for matrix range queries): P[i][j] = sum of rectangle arr[0..i-1][0..j-1]. Build: P[i][j] = arr[i-1][j-1] + P[i-1][j] + P[i][j-1] - P[i-1][j-1]. Query rectangle (r1,c1) to (r2,c2): P[r2+1][c2+1] - P[r1][c2+1] - P[r2+1][c1] + P[r1][c1].
io/thecodeforge/algo/PrefixSum2D.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package io.thecodeforge.algo;
import java.util.Arrays;
publicclassPrefixSum2D {
privatefinallong[][] prefix;
/**
* Builds the 2D prefix sum array in O(mn).
* P[i][j] = sum of rectangle arr[0..i-1][0..j-1].
*/
publicPrefixSum2D(int[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
prefix = newlong[rows + 1][cols + 1];
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= cols; j++) {
prefix[i][j] = matrix[i - 1][j - 1]
+ prefix[i - 1][j]
+ prefix[i][j - 1]
- prefix[i - 1][j - 1];
}
}
}
/**
* Returns the sum of the rectangle from (r1,c1) to (r2,c2) inclusive. O(1).
* Inclusion-exclusion: include bottom-right, exclude top row, exclude left column, add back corner.
*/
publiclongrectangleSum(int r1, int c1, int r2, int c2) {
return prefix[r2 + 1][c2 + 1]
- prefix[r1][c2 + 1]
- prefix[r2 + 1][c1]
+ prefix[r1][c1];
}
publicstaticvoidmain(String[] args) {
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
PrefixSum2D ps = newPrefixSum2D(matrix);
// Sum of entire matrix: 1+2+...+12 = 78System.out.println("Total sum: " + ps.rectangleSum(0, 0, 2, 3));
// Sum of submatrix [1,1] to [2,2]: 6+7+10+11 = 34System.out.println("Submatrix [1,1..2,2]: " + ps.rectangleSum(1, 1, 2, 2));
// Sum of top-left 2x2: 1+2+5+6 = 14System.out.println("Top-left 2x2: " + ps.rectangleSum(0, 0, 1, 1));
// Single element: matrix[2][3] = 12System.out.println("Single element [2,3]: " + ps.rectangleSum(2, 3, 2, 3));
}
}
Output
Total sum: 78
Submatrix [1,1..2,2]: 34
Top-left 2x2: 14
Single element [2,3]: 12
The Inclusion-Exclusion Formula for 2D
P[r2+1][c2+1]: sum of rectangle from origin to (r2, c2). The big rectangle.
P[r1][c2+1]: sum above the target rectangle. Subtract this.
P[r2+1][c1]: sum to the left of the target rectangle. Subtract this.
P[r1][c1]: the top-left corner, subtracted twice. Add it back once.
A computer vision pipeline computed integral images (2D prefix sums) for every frame in a 4K video stream (3840x2160 pixels). The integral image enabled O(1) rectangle sum queries for Haar-like feature detection in face recognition. Without integral images, each feature evaluation summed a rectangle of pixels — O(area) per feature. With 5,000 features per frame at 30 fps, the integral image reduced per-frame computation from ~2 billion additions to ~150,000 additions (the build cost). This enabled real-time face detection on commodity hardware.
Key Takeaway
2D prefix sums extend the 1D technique to matrices using inclusion-exclusion. The build is O(mn), the query is O(1). The +P[r1][c1] term in the query formula is mandatory — omitting it double-subtracts the top-left corner. This is the basis of integral images in computer vision.
Always trace P[0]=0. If it is not 0, the sentinel is missing.
Trace a query starting at l=0. This tests the sentinel: P[r+1] - P[0] = P[r+1].
Trace a query in the middle. This tests the subtraction: P[r+1] - P[l].
Trace a single-element query: l=r. Result should be arr[l].
If any trace is wrong, the build or the formula has an off-by-one.
Production Insight
A team implemented prefix sums for a financial reconciliation system. The build was correct but the query formula used P[r] - P[l] instead of P[r+1] - P[l]. This excluded the element at index r from every query. The bug was invisible for single-element queries (l=r, P[r] - P[l] = 0, which was obviously wrong) but silently wrong for multi-element queries. The fix: always verify with a manual trace of at least one multi-element query.
Key Takeaway
Manual tracing catches 90% of prefix sum bugs. Print the prefix array, trace a query starting at index 0 (tests the sentinel), and trace a middle query (tests the formula). The two details that cause bugs: P[0]=0 sentinel and P[r+1] not P[r].
Difference Arrays — The Inverse of Prefix Sums
Prefix sums answer range queries in O(1) but require O(n) updates. Difference arrays invert this: they support O(1) range updates but require O(n) to read the final state. The two techniques are complementary.
A difference array D is defined as D[0] = arr[0], D[i] = arr[i] - arr[i-1]. To add value v to all elements in arr[l..r], set D[l] += v and D[r+1] -= v. To recover the final array, take the prefix sum of D.
This is ideal for problems where you perform many range updates and then read the final array once — for example, applying salary adjustments to a range of employees, then computing the final payroll.
io/thecodeforge/algo/DifferenceArray.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package io.thecodeforge.algo;
import java.util.Arrays;
publicclassDifferenceArray {
privatefinallong[] diff;
privatefinalint length;
/**
* Initializes a difference array from the original array.
* D[0] = arr[0], D[i] = arr[i] - arr[i-1].
*/
publicDifferenceArray(int[] arr) {
length = arr.length;
diff = new long[length + 1]; // +1 for the r+1 boundary
diff[0] = arr[0];
for (int i = 1; i < length; i++) {
diff[i] = arr[i] - arr[i - 1];
}
}
/**
* Adds value v to all elements in arr[l..r] inclusive. O(1).
*/
publicvoidrangeUpdate(int l, int r, long v) {
diff[l] += v;
if (r + 1 < diff.length) {
diff[r + 1] -= v;
}
}
/**
* Reconstructs the final array by taking the prefix sum of the difference array. O(n).
*/
publiclong[] getResult() {
long[] result = newlong[length];
result[0] = diff[0];
for (int i = 1; i < length; i++) {
result[i] = result[i - 1] + diff[i];
}
return result;
}
publicstaticvoidmain(String[] args) {
int[] salaries = {50000, 60000, 55000, 70000, 45000};
System.out.println("Original: " + Arrays.toString(salaries));
DifferenceArray da = newDifferenceArray(salaries);
// Give a $5000 raise to employees 1 through 3
da.rangeUpdate(1, 3, 5000);
System.out.println("After $5k raise to [1..3]: " + Arrays.toString(da.getResult()));
// Apply a $2000 bonus to all employees (0 through 4)
da.rangeUpdate(0, 4, 2000);
System.out.println("After $2k bonus to all: " + Arrays.toString(da.getResult()));
}
}
Output
Original: [50000, 60000, 55000, 70000, 45000]
After $5k raise to [1..3]: [50000, 65000, 60000, 75000, 45000]
After $2k bonus to all: [52000, 67000, 62000, 77000, 47000]
Prefix Sum vs Difference Array: Dual Operations
Prefix sum: O(n) build, O(1) query, O(n) update. Best for read-heavy workloads.
Difference array: O(1) range update, O(n) read. Best for write-heavy workloads.
They are inverses: prefix sum of a difference array recovers the original array.
Use prefix sums for: analytics dashboards, range sum queries on static data.
Use difference arrays for: batch salary adjustments, range increment operations.
Production Insight
A scheduling system applied shift adjustments (overtime pay, deductions) to ranges of employees. With 50,000 employees and 10,000 range adjustments per payroll cycle, a naive O(n) per update approach was 500 million operations. Using a difference array: 10,000 updates x O(1) = 10,000 operations, plus one O(n) reconstruction = 50,000 operations. Total: 60,000 operations vs 500 million — an 8,333x reduction.
Key Takeaway
Difference arrays are the inverse of prefix sums: O(1) range updates, O(n) final read. Use them when you have many updates and few reads. For workloads requiring both queries and updates, use a Fenwick Tree (O(log n) for both).
Fenwick Tree vs Prefix Sum — Choosing the Right Tool
Prefix sums are optimal for static data: O(n) build, O(1) query, but O(n) update. When the array changes frequently, this O(n) rebuild cost becomes prohibitive. Fenwick Trees (Binary Indexed Trees) provide O(log n) for both point updates and range queries, at the cost of more complex implementation.
The trade-off is clear: prefix sums are simpler and faster for queries (O(1) vs O(log n)), but Fenwick Trees handle dynamic data without rebuilding. Choose based on your update-to-query ratio.
io/thecodeforge/algo/FenwickTree.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package io.thecodeforge.algo;
publicclassFenwickTree {
privatefinallong[] tree;
privatefinalint n;
/**
* Builds a FenwickTree from an array. O(n log n).
* Supports point update and prefix sum query in O(log n).
*/
publicFenwickTree(int[] arr) {
n = arr.length;
tree = newlong[n + 1];
for (int i = 0; i < n; i++) {
update(i, arr[i]);
}
}
/**
* Adds delta to arr[index]. O(log n).
*/
publicvoidupdate(int index, long delta) {
for (int i = index + 1; i <= n; i += i & (-i)) {
tree[i] += delta;
}
}
/**
* Returns the sum of arr[0..index] inclusive. O(log n).
*/
publiclongprefixSum(int index) {
long sum = 0;
for (int i = index + 1; i > 0; i -= i & (-i)) {
sum += tree[i];
}
return sum;
}
/**
* Returns the sum of arr[l..r] inclusive. O(log n).
*/
publiclongrangeSum(int l, int r) {
returnprefixSum(r) - (l > 0 ? prefixSum(l - 1) : 0);
}
publicstaticvoidmain(String[] args) {
int[] arr = {3, 1, 4, 1, 5, 9, 2, 6};
FenwickTree ft = newFenwickTree(arr);
System.out.println("sum(2..5) = " + ft.rangeSum(2, 5)); // 19System.out.println("sum(0..7) = " + ft.rangeSum(0, 7)); // 31// Update arr[3] from 1 to 10 (delta = +9)
ft.update(3, 9);
System.out.println("After update arr[3]+=9:");
System.out.println("sum(2..5) = " + ft.rangeSum(2, 5)); // 4+10+5+9 = 28System.out.println("sum(0..7) = " + ft.rangeSum(0, 7)); // 40
}
}
Output
sum(2..5) = 19
sum(0..7) = 31
After update arr[3]+=9:
sum(2..5) = 28
sum(0..7) = 40
Watch Out: Prefix Sum + Updates = O(n) Rebuild
Prefix sum: O(1) query, O(n) update. Best for static data with many queries.
Fenwick Tree: O(log n) query, O(log n) update. Best for dynamic data.
Segment Tree: O(log n) query, O(log n) update. More flexible (supports min, max, gcd) but more complex.
Decision rule: update-to-query ratio. If updates are rare, prefix sum wins on query speed.
Decision rule: array size. For arrays under 10,000 elements, the log factor is negligible. Use prefix sum for simplicity.
Production Insight
A real-time leaderboard maintained scores for 500,000 players. Each game round updated 10,000 player scores (point updates) and queried the top-K players (range queries) 1,000 times per second. With prefix sums, each update required a full O(n) rebuild: 10,000 updates x 500,000 = 5 billion operations per round. With a Fenwick Tree: 10,000 updates x log2(500K) ~ 19 = 190,000 operations, plus 1,000 queries x 19 = 19,000 operations. Total: 209,000 operations vs 5 billion — a 24,000x reduction. The leaderboard latency dropped from 12 seconds to 0.5 milliseconds per round.
Key Takeaway
Prefix sums are O(1) query but O(n) update. Fenwick Trees are O(log n) for both. Choose prefix sums for static data with many queries. Choose Fenwick Trees for dynamic data with frequent updates. The crossover point depends on the update-to-query ratio and array size.
● Production incidentPOST-MORTEMseverity: high
Analytics Dashboard 47x Slower After Removing Prefix Sum Optimization
Symptom
Dashboard page load time increased from 120ms to 5,600ms after a code refactor. P99 latency breached the 2-second SLO. CPU utilization on the analytics service jumped from 12% to 89%. No database changes, no traffic increase, no infrastructure changes.
Assumption
A database query regression was introduced during the refactor. The team spent 6 hours profiling SQL queries, adding indexes, and checking connection pools. All database metrics were normal.
Root cause
The dashboard rendered 200 revenue charts, each requiring a range sum over a 90-day window (2,160 hourly data points). The original code precomputed a prefix sum array during data ingestion: O(n) build, O(1) per chart query. The loop over the 2,160 data points for each chart: O(n) per query. Total operations: 200 charts x 2,160 iterations = 432,000 additions per page load. With the prefix sum: 200 charts x 1 subtraction = 200 operations. The refactor increased computation by 2,160x — from 200 operations to 432,000 operations per page load.
Fix
1. Restored the prefix sum precomputation during data ingestion. Build cost: O(n) once per data update. Query cost: O(1) per chart.
2. Added a unit test that asserts dashboard load completes in under 200ms with 200 charts. This test would have caught the regression.
3. Added a performance annotation: @PrefixSumOptimized on the range query method, with a comment explaining why the prefix sum is required and what happens without it.
4. Added a metric: dashboard_range_query_operations_total to track the number of addition refactor replaced this with a direct operations per page load. Alert if it exceeds 1,000.
Key lesson
Prefix sums are not a micro-optimization. At 200 queries over 2,160 elements, the difference is 432,000 operations vs 200 operations — a 2,160x speedup.
Always add a performance regression test for critical paths. The refactor passed all functional tests but broke performance silently.
Document why an optimization exists. The refactor author did not know why the prefix sum was there and removed it as 'unnecessary complexity.'
Prefix sums are ideal for read-heavy, static datasets. If the data changes infrequently (e.g., hourly ingestion), the O(n) rebuild cost is negligible compared to the O(1) query savings.
Track operation counts, not just latency. The dashboard latency spike was a symptom; the 2,160x increase in addition operations was the root cause.
Production debug guideSymptom-first investigation path for prefix sum bugs.6 entries
Symptom · 01
Range sum query returns wrong value — off by one or off by the first element.
→
Fix
Check the P[0]=0 sentinel. If missing, sum(arr[0..r]) requires special handling. Also verify the query formula: sum(l, r) = P[r+1] - P[l], not P[r] - P[l].
Symptom · 02
ArrayIndexOutOfBoundsException on range query when r = array length - 1.
→
Fix
The prefix array has size n+1, not n. If you allocated P with size n, P[r+1] at r=n-1 accesses P[n], which is out of bounds. Allocate P with size arr.length + 1.
Symptom · 03
2D prefix sum returns wrong rectangle sum — off by a corner.
→
Fix
The inclusion-exclusion formula must subtract P[r1][c2+1] and P[r2+1][c1] and add back P[r1][c1]. Missing the add-back double-subtracts the top-left corner. Verify: P[r2+1][c2+1] - P[r1][c2+1] - P[r2+1][c1] + P[r1][c1].
Symptom · 04
Prefix sum returns correct values for some queries but wrong for others.
→
Fix
Check if the original array was modified after the prefix sum was built. Prefix sums are a snapshot — any update to the original array invalidates the prefix array. Rebuild after every update.
Symptom · 05
Difference array produces wrong final values after range updates.
→
Fix
Verify the prefix sum of the difference array is computed correctly. diff[l] += v and diff[r+1] -= v. Then the final array is the prefix sum of diff. Check that r+1 does not exceed the array bounds.
Symptom · 06
Dashboard or analytics query is unexpectedly slow despite using prefix sums.
→
Fix
Check if the prefix sum is being rebuilt on every query instead of once during data ingestion. If the build happens inside the query handler, you pay O(n) per query instead of O(1).
★ Prefix Sum Triage CommandsRapid checks to isolate prefix sum bugs in production.
Range sum returns wrong value.−
Immediate action
Print the prefix array and verify manually.
Commands
System.out.println(Arrays.toString(prefix)) — verify P[0]=0 and each P[i] = P[i-1] + arr[i-1]
2D prefix sums extend the technique to matrix rectangle queries using inclusion-exclusion.
4
Updates require rebuilding the entire prefix array
use Fenwick Tree for dynamic updates.
5
Difference arrays are the inverse
O(1) range updates, O(n) to read the final array.
6
Use long for the prefix array to prevent integer overflow on large cumulative sums.
7
Prefix sums + HashMap solve subarray-sum-equals-k in O(n)
a top-5 interview pattern.
8
Always trace a query starting at index 0 to verify the P[0]=0 sentinel is correct.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
FAQ · 6 QUESTIONS
Frequently Asked Questions
01
Why is the prefix array size n+1 instead of n?
The extra element at index 0 (set to 0) acts as a base case that simplifies the range query formula. Without it, you would need a special case for queries starting at index 0. With P[0]=0, sum(arr[0..r]) = P[r+1] - P[0] = P[r+1], which works uniformly.
Was this helpful?
02
Can prefix sums handle updates to the original array?
Not efficiently. If the original array changes, you must rebuild the entire prefix array in O(n). For applications requiring both range queries and point updates, use a Fenwick Tree (Binary Indexed Tree) or Segment Tree, which support both operations in O(log n).
Was this helpful?
03
What is a difference array and how does it relate to prefix sums?
A difference array is the inverse of a prefix sum. It enables range updates in O(1): to add value v to all elements arr[l..r], set diff[l]+=v and diff[r+1]-=v. To read the final array, take the prefix sum of the difference array. Difference arrays are useful for bulk range-update problems where you query the final state only once.
Was this helpful?
04
How do prefix sums solve the 'subarray sum equals k' problem?
Compute the prefix sum P. For each index i, check if P[i] - k exists in a HashMap of previously seen prefix sums. If it does, the subarray between that index and i sums to k. This is O(n) time, O(n) space. The insight: P[i] - P[j] = k means the subarray arr[j+1..i] sums to k.
Was this helpful?
05
When should I use a Fenwick Tree instead of prefix sums?
Use a Fenwick Tree when the array receives frequent updates (point or range). Prefix sums require O(n) rebuild per update; Fenwick Trees support O(log n) updates and O(log n) queries. If queries vastly outnumber updates (e.g., 1M queries, 10 updates), prefix sums are simpler and faster for queries (O(1) vs O(log n)).
Was this helpful?
06
Can prefix sums overflow?
Yes. If the input array contains int values and the cumulative sum exceeds Integer.MAX_VALUE (2.1 billion), the prefix array overflows silently. Always use long for the prefix array. A common case: 1M elements averaging 10,000 each = 10 billion total, which overflows int.