Prefix sums give range queries on a static array. Difference arrays give range updates that are read at the end. Each is the inverse transform of the other. Check them before reaching for any tree.

Prefix sumDifference array
Fast operationrange queryrange update
Slow operationupdate ()query ()
Build
Finalise— prefix pass
Best whenall updates precede all queriesall updates precede all queries (the other way round)

Prefix sums

vector<ll> p(n + 1);                          // p[i] = a[0] + ... + a[i-1]
for (int i = 0; i < n; i++) p[i + 1] = p[i] + a[i];
// sum of a[l..r) = p[r] - p[l]

Half-open indices with remove every special case at the left edge.

2D: , and the rectangle sum is the four-term inclusion-exclusion. In dimensions it takes terms, or one prefix pass per axis (that’s cheaper to build: ).

What can be prefixed: any group operation (sum, XOR, product of non-zero values mod prime). Min, max and gcd aren’t invertible, so use a sparse table (Sparse Table) or prefix and suffix arrays when you only need to exclude one element:

// gcd of the array without a[i]: pre[i] = gcd(a[0..i)), suf[i] = gcd(a[i..n))
ll without(int i) { return gcd(pre[i], suf[i + 1]); }

The general version of this trick: for any associative operation with an identity, pre[i] aggregates and suf[i] aggregates , and combine(pre[i], suf[i+1]) excludes position without needing an inverse (unlike subtracting from a prefix sum, which only works when the operation is invertible). Preserve argument order for non-commutative operations, and make sure the sentinel identity values actually match the operation (0 for sum/XOR, 1 for product, a suitably large/small value for min/max). Preprocessing and every exclusion query cost total.

TrickUse
prefix XORsubarray XOR in
prefix counts per value”how many in “
prefix of “is constant”
prefix min/maxnot decomposable — use a sparse table
prefix product mod range product, with modular inverses
prefix sums of the sorted array”sum of the smallest”

Counting subarrays = counting pairs of prefixes

A subarray is a pair of prefixes, so “count subarrays with property ” becomes “count pairs with ”.

Subarrays withPairs of prefixesTool
sum hash map of counts
sum divisible by count residues; remember
XOR hash map; for “XOR ” or max XOR use a binary trie
equal number of 0s and 1smap , then sum hash map, or offset array
sum in BIT over compressed prefixes, or merge sort
longest with sum first occurrence of each prefixmap value first index
max sumrunning minimum (Kadane)
max sum with length in sliding window minimum of monotonic deque
average subtract , then sum binary search on
median by comparing with , then sum (or )binary search on
balanced brackets, never below and sparse table on , or stack

Difference arrays

vector<ll> d(n + 1);
auto add = [&](int l, int r, ll x) { d[l] += x; d[r] -= x; };   // a[l..r) += x
// finalize: prefix-sum d to recover the array

updates plus one pass is . Uses: interval coverage counts (“how many intervals contain each point”), booking problems, sweep events, and grid stamping.

2D: add to rows and columns with at , at and , at . Finalize with a 2D prefix sum.

Polynomial updates via higher-order differences. Adding a polynomial of degree over a range needs levels of differences. For an arithmetic progression on positions , with the second difference array (prefix-sum twice to finalize):

D[l]         += a;
D[l + 1]     += s - a;
D[l + m]     -= a + m * s;              // a + (m-1)s is the last term
D[l + m + 1] += a + (m - 1) * s;

When in doubt, derive boundary terms by writing the first difference array for a tiny example. For degree in general, add -shaped patterns: the -th difference of is a single 1.

Tested against direct double prefix-summing, comparing the reconstructed array to the intended AP on random .

Interleaved updates and queries: a Fenwick tree over the difference array gives range add with point query. Two Fenwick trees give range add with range sum, using (Fenwick Tree).

On trees

Let be the sum of values on the root-to- path. Then (drop the last term for edge values).

Path updates with all reads at the end (the tree difference array): to add on the path –, do d[u] += x; d[v] += x; d[lca] -= x; d[parent(lca)] -= x;. Then each vertex’s value is the sum of d over its subtree, which one DFS computes. For edge values stored at the child endpoint: d[u] += x; d[v] += x; d[lca] -= 2x.

Subtree updates and queries become ranges after an Euler tour (Euler Tour).

Decision order

  1. No updates: prefix sums, or a sparse table for idempotent operations.
  2. All updates before all queries: difference array.
  3. Queries offline: sort and sweep with a BIT.
  4. Point update with prefix query: BIT.
  5. Anything else: segment tree, possibly lazy.

Pitfalls

  • Prefix sums of values up to reach : use ll.
  • Counting “subarrays with sum divisible by ” with negative numbers: normalise residues into .
  • Hash maps keyed by prefix sums are hackable on Codeforces: use a safe hash or sort and compress instead.