Submatrix Sum Queries

medium Matrix (2D arrays)

Problem

A matrix has r rows and c columns. Then q queries come. Each query has four numbers r1 c1 r2 c2 (counted from 0): print the sum of all numbers in the rectangle from row r1 to row r2 and from column c1 to column c2 (both ends included). Input: the first line is r c, then the r rows, then the line with q, then the q queries.

Constraints

  • 1 <= r, c <= 1000
  • 1 <= q <= 10^5

Examples

Input

2 2
1 2
3 4
1
0 0 1 1

Output

10

Solutions

Best approachTime O(r c + q)Space O(r c)

One pass builds a table where each cell holds the sum of the rectangle from the top-left corner. After that, each query needs only four table values (inclusion-exclusion), so it takes O(1).

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Rectangle sums.
 * Input   : The matrix and the queries.
 * Output  : One sum per query.
 * Approach: 2D prefix sums
 * Time    : O(r c + q)
 * Space   : O(r c)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        String[] head = lines[0].split(" ");
        int rows = Integer.parseInt(head[0]);
        int cols = Integer.parseInt(head[1]);
        // Step 1: prefix[i][j] is the sum of the rectangle up to (i - 1, j - 1).
        // The extra first row and column hold zeros.
        long[][] prefix = new long[rows + 1][cols + 1];
        for (int i = 1; i <= rows; i++) {
            String[] part = lines[i].split(" ");
            for (int j = 1; j <= cols; j++) {
                prefix[i][j] = Long.parseLong(part[j - 1]) + prefix[i - 1][j] + prefix[i][j - 1] - prefix[i - 1][j - 1];
            }
        }
        int queries = Integer.parseInt(lines[rows + 1]);
        String[] out = new String[queries];
        for (int k = 0; k < queries; k++) {
            String[] q = lines[rows + 2 + k].split(" ");
            int r1 = Integer.parseInt(q[0]);
            int c1 = Integer.parseInt(q[1]);
            int r2 = Integer.parseInt(q[2]) + 1;
            int c2 = Integer.parseInt(q[3]) + 1;
            // Step 2: Big rectangle, minus the strip above, minus the strip on the left, plus the corner that was removed twice.
            out[k] = String.valueOf(prefix[r2][c2] - prefix[r1][c2] - prefix[r2][c1] + prefix[r1][c1]);
        }
        return out;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(String.join("\n", solve(lines)));
    }
}
Hints (2)
  1. Why is the corner added back?
  2. What is the cost of one query?