AlgoMaster Logo

Range Sum Query 2D - Immutable

mediumFrequencyUpdated September 21, 2026

Understanding the Problem

We're given a 2D grid of integers and need to answer rectangle sum queries efficiently. Each query hands us the top-left and bottom-right corners of a rectangle, and we need to return the sum of all elements inside it.

A single query is easy: loop through the rectangle and add everything up. The difficulty is that sumRegion can be called up to 10,000 times, and the problem requires O(1) per query. That rules out re-scanning the rectangle each time and forces us to do preprocessing during construction that lets any later query resolve in constant time.

The 1D version of this problem (Range Sum Query - Immutable) is solved with a prefix sum array, where one subtraction gives the sum of any subarray in O(1). The question is whether that idea extends to two dimensions.

Key Constraints:

  • 1 <= m, n <= 200 and at most 10^4 calls → A 200x200 matrix scanned per query across 10^4 queries is 4 10^8 cell reads in the worst case, and the problem requires O(1) per query regardless. Both point to the same target: O(m n) preprocessing, O(1) per query.
  • -10^4 <= matrix[i][j] <= 10^4 → Values can be negative, so any approach must handle subtraction and cannot assume sums only grow. The largest possible rectangle sum is 200 200 10^4 = 4 * 10^8, which fits in a 32-bit signed int, so int is safe for the accumulators.

Approach 1: Brute Force

Intuition

Do exactly what the problem describes: for each query, iterate through every cell in the rectangle and add up the values. The constructor stores the matrix and does no preprocessing.

This is correct but slow on many queries over a large matrix. Each query takes O(m * n) in the worst case (a rectangle spanning the entire matrix), and with up to 10,000 queries that work is repeated from scratch every time even though the matrix never changes.

Algorithm

  1. In the constructor, store the matrix.
  2. For each sumRegion call, initialize a sum variable to 0.
  3. Loop through every row from row1 to row2.
  4. For each row, loop through every column from col1 to col2.
  5. Add matrix[row][col] to the running sum.
  6. Return the sum.

Visualization and Code

Loading animation...

The next approach precomputes row-wise prefix sums so each row's contribution to a query becomes a single subtraction instead of a scan.

Approach 2: 1D Prefix Sums (Row-wise)

Intuition

Compute prefix sums for each row independently. With a per-row prefix array, the sum of any segment within a row is one subtraction. A rectangle query then loops only over the rows from row1 to row2, taking each row's contribution in O(1) instead of scanning that row's columns.

This brings the per-query cost from O(m * n) down to O(m), and it is the direct one-dimensional version of the two-dimensional prefix sum in the next approach.

For each row i, build a prefix array where rowPrefix[i][j] = sum of matrix[i][0..j-1]. The sum of row i from column col1 to col2 is rowPrefix[i][col2 + 1] - rowPrefix[i][col1]. The leading zero at rowPrefix[i][0] is what lets col1 = 0 work without a special case.

Algorithm

  1. In the constructor, build a prefix sum array for each row. rowPrefix[i][j] stores the sum of the first j elements in row i.
  2. For each sumRegion call, initialize a sum variable to 0.
  3. Loop through rows from row1 to row2.
  4. For each row, compute that row's contribution using the prefix array: rowPrefix[r][col2 + 1] - rowPrefix[r][col1].
  5. Return the sum.

Visualization and Code

Loading animation...

Row prefixes still require a loop over up to m rows per query. The next approach precomputes sums in both dimensions at once, reducing every query to a fixed number of lookups regardless of rectangle size.

Approach 3: 2D Prefix Sum (Optimal)

Intuition

The 2D prefix sum precomputes one value per cell and answers every query in constant time using inclusion-exclusion.

Define a prefix sum matrix where prefix[i][j] stores the sum of all elements in the rectangle from (0, 0) to (i-1, j-1). Each entry is the sum of one full corner-anchored rectangle. Any arbitrary rectangle sum can then be expressed as a combination of four such corner rectangles.

To get the sum of the rectangle from (row1, col1) to (row2, col2), start with prefix[row2+1][col2+1], the sum of everything from the origin to the bottom-right corner. That overcounts: it includes the band above the target rectangle and the band to its left. Subtract both:

  • Subtract prefix[row1][col2+1] (everything above the rectangle)
  • Subtract prefix[row2+1][col1] (everything to the left of the rectangle)

The two bands overlap in the top-left corner region, so that corner has now been subtracted twice. Add it back once:

  • Add prefix[row1][col1] (top-left corner, double-subtracted)

What remains is exactly the target rectangle: four lookups and three arithmetic operations per query.

Algorithm

  1. Create a prefix sum matrix of size (m+1) x (n+1), initialized to zeros. The extra row and column handle boundary cases cleanly (no special-casing row 0 or column 0).
  2. Fill the prefix sum matrix. For each cell (i, j), compute: prefix[i+1][j+1] = matrix[i][j] + prefix[i][j+1] + prefix[i+1][j] - prefix[i][j].
  3. For each sumRegion(row1, col1, row2, col2) call, return: prefix[row2+1][col2+1] - prefix[row1][col2+1] - prefix[row2+1][col1] + prefix[row1][col1].

Visualization and Code

Loading animation...