{ }codelper
prefix sums2D lists64-bit integersP0092

Fast rectangle sums on a grid

A grid with r rows and c columns has one integer in each cell.
The top row is row 1 and the leftmost column is column 1.
q questions follow; each gives four numbers r₁ c₁ r₂ c₂ and asks for 'the sum of all numbers in the rectangle made of rows r₁ to r₂ and columns c₁ to c₂ (both ends included)'.
Print each answer on its own line, in the order given. The first line gives r, c and q, then r lines each give that row's c numbers, then q lines give the questions, all separated by spaces.

Input
1 ≤ r, c ≤ 100, 1 ≤ q ≤ 10,000, every cell is between -10⁶ and 10⁶, 1 ≤ r₁ ≤ r₂ ≤ r, 1 ≤ c₁ ≤ c₂ ≤ c
Output
q lines, the sum of the rectangle for each question
Example 1 · stdin
3 4 3
1 2 3 4
5 6 7 8
9 10 11 12
1 1 3 4
2 2 3 3
1 4 3 4
stdout
78
34
24
main.py
Input (stdin)

When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).

$ Ready

Open this on a computer to write and run code. On mobile you can read the problem and the solutions.

In other languagesShow solutions by language · 8 languages

Adding up the cells again for each question costs up to 10,000 questions × 10,000 cells = 100 million additions.
Python cannot finish in time, and Craykon passes its execution-step limit (about 50 million) and stops.
Build the 2D prefix sum P[i][j] = 'sum of the rectangle from (1,1) to (i,j)' once with P[i][j] = a[i][j] + P[i-1][j] + P[i][j-1] - P[i-1][j-1] (row 0 and column 0 are 0); then each answer is P[r₂][c₂] - P[r₁-1][c₂] - P[r₂][c₁-1] + P[r₁-1][c₁-1].
Three traps: subtracting with r₁, c₁ instead of r₁-1, c₁-1 drops the top row and left column.
It is easy to forget to add back the top-left piece that was subtracted twice.
And sums reach 10⁴ × 10⁶ = 10¹⁰, which overflows int (about 2.1 billion) in C, C++, Java and C# — use long/long long.
Python integers are unbounded, and JavaScript, TypeScript and Craykon are exact up to 2^53, so they are fine.
Making a 2D array differs by language: Python [[0] * (c + 1) for _ in range(r + 1)] ([[0] * (c + 1)] * (r + 1) is wrong: every row is the same list), JS Array.from({ length: r + 1 }, () => new Array(c + 1).fill(0)), Java new long[r + 1][c + 1] (zero-filled), C# rectangular array new long[r + 1, c + 1] with P[i, j], C a global long long P[101][101], C++ vector<vector<long long>>.
Craykon stacks a NewList(c + 1, 0) per row with P.Add(…) — each row has 101 cells, far under the list limit of 10,000 items.

Pythonmain.py · 19 lines
import sys data = sys.stdin.buffer.read().split()r, c, q = int(data[0]), int(data[1]), int(data[2])pos = 3 # P[i][j] = 왼쪽 위 (1,1)부터 (i,j)까지 직사각형의 합. 0번째 줄·칸은 0으로 둔다P = [[0] * (c + 1) for _ in range(r + 1)]for i in range(1, r + 1):    for j in range(1, c + 1):        P[i][j] = int(data[pos]) + P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1]        pos += 1 out = []for _ in range(q):    r1, c1, r2, c2 = map(int, data[pos:pos + 4])    pos += 4    out.append(P[r2][c2] - P[r1 - 1][c2] - P[r2][c1 - 1] + P[r1 - 1][c1 - 1])print("\n".join(map(str, out)))
JavaScriptmain.js · 19 lines
const t = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [r, c, q] = t;let pos = 3; // P[i][j] = 왼쪽 위 (1,1)부터 (i,j)까지 직사각형의 합. 0번째 줄·칸은 0으로 둔다const P = Array.from({ length: r + 1 }, () => new Array(c + 1).fill(0));for (let i = 1; i <= r; i++) {  for (let j = 1; j <= c; j++) {    P[i][j] = t[pos++] + P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1];  }} const out = [];for (let k = 0; k < q; k++) {  const [r1, c1, r2, c2] = t.slice(pos, pos + 4);  pos += 4;  out.push(P[r2][c2] - P[r1 - 1][c2] - P[r2][c1 - 1] + P[r1 - 1][c1 - 1]);}console.log(out.join("\n"));
TypeScriptmain.ts · 20 lines
import { readFileSync } from "node:fs";const t: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [r, c, q] = t;let pos = 3; // P[i][j] = 왼쪽 위 (1,1)부터 (i,j)까지 직사각형의 합. 0번째 줄·칸은 0으로 둔다const P: number[][] = Array.from({ length: r + 1 }, () => new Array(c + 1).fill(0));for (let i = 1; i <= r; i++) {  for (let j = 1; j <= c; j++) {    P[i][j] = t[pos++] + P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1];  }} const out: number[] = [];for (let k = 0; k < q; k++) {  const [r1, c1, r2, c2] = t.slice(pos, pos + 4);  pos += 4;  out.push(P[r2][c2] - P[r1 - 1][c2] - P[r2][c1 - 1] + P[r1 - 1][c1 - 1]);}console.log(out.join("\n"));
JavaMain.java · 30 lines
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(br.readLine());        int r = Integer.parseInt(st.nextToken()), c = Integer.parseInt(st.nextToken()), q = Integer.parseInt(st.nextToken());         // P[i][j] = 왼쪽 위 (1,1)부터 (i,j)까지 직사각형의 합. 0번째 줄·칸은 0(자바 배열은 0으로 채워진다)        long[][] P = new long[r + 1][c + 1];        for (int i = 1; i <= r; i++) {            st = new StringTokenizer(br.readLine());            for (int j = 1; j <= c; j++) {                P[i][j] = Long.parseLong(st.nextToken()) + P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1];            }        }         StringBuilder out = new StringBuilder();        for (int k = 0; k < q; k++) {            st = new StringTokenizer(br.readLine());            int r1 = Integer.parseInt(st.nextToken()), c1 = Integer.parseInt(st.nextToken());            int r2 = Integer.parseInt(st.nextToken()), c2 = Integer.parseInt(st.nextToken());            out.append(P[r2][c2] - P[r1 - 1][c2] - P[r2][c1 - 1] + P[r1 - 1][c1 - 1]).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 26 lines
using System;using System.Text; class Program{    static void Main()    {        string[] t = Console.In.ReadToEnd().Split((char[])null, StringSplitOptions.RemoveEmptyEntries);        int r = int.Parse(t[0]), c = int.Parse(t[1]), q = int.Parse(t[2]);        int pos = 3;         // P[i, j] = 왼쪽 위 (1,1)부터 (i,j)까지 직사각형의 합. 0번째 줄·칸은 0        long[,] P = new long[r + 1, c + 1];        for (int i = 1; i <= r; i++)            for (int j = 1; j <= c; j++)                P[i, j] = long.Parse(t[pos++]) + P[i - 1, j] + P[i, j - 1] - P[i - 1, j - 1];         var sb = new StringBuilder();        for (int k = 0; k < q; k++, pos += 4)        {            int r1 = int.Parse(t[pos]), c1 = int.Parse(t[pos + 1]), r2 = int.Parse(t[pos + 2]), c2 = int.Parse(t[pos + 3]);            sb.Append(P[r2, c2] - P[r1 - 1, c2] - P[r2, c1 - 1] + P[r1 - 1, c1 - 1]).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 24 lines
#include <iostream>#include <vector> int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    int r, c, q;    std::cin >> r >> c >> q;     // P[i][j] = 왼쪽 위 (1,1)부터 (i,j)까지 직사각형의 합. 0번째 줄·칸은 0으로 둔다    std::vector<std::vector<long long>> P(r + 1, std::vector<long long>(c + 1, 0));    for (int i = 1; i <= r; i++) {        for (int j = 1; j <= c; j++) {            long long v;            std::cin >> v;            P[i][j] = v + P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1];        }    }    for (int k = 0; k < q; k++) {        int r1, c1, r2, c2;        std::cin >> r1 >> c1 >> r2 >> c2;        std::cout << P[r2][c2] - P[r1 - 1][c2] - P[r2][c1 - 1] + P[r1 - 1][c1 - 1] << '\n';    }}
Cmain.c · 24 lines
#include <stdio.h> #define MAX 100 /* P[i][j] = 왼쪽 위 (1,1)부터 (i,j)까지 직사각형의 합. 0번째 줄·칸은 0(전역 배열은 0으로 시작) */static long long P[MAX + 1][MAX + 1]; int main(void) {    int r, c, q;    scanf("%d %d %d", &r, &c, &q);    for (int i = 1; i <= r; i++) {        for (int j = 1; j <= c; j++) {            long long v;            scanf("%lld", &v);            P[i][j] = v + P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1];        }    }    for (int k = 0; k < q; k++) {        int r1, c1, r2, c2;        scanf("%d %d %d %d", &r1, &c1, &r2, &c2);        printf("%lld\n", P[r2][c2] - P[r1 - 1][c2] - P[r2][c1 - 1] + P[r1 - 1][c1 - 1]);    }    return 0;}
Craykonmain.cray · 29 lines
첫줄 = Console.ReadNumbers();r = 첫줄[0];c = 첫줄[1];q = 첫줄[2]; // P[i][j] = 왼쪽 위 (1,1)부터 (i,j)까지 직사각형의 합. 0번째 줄·칸은 0으로 둔다P = [];for (i = 0; i <= r; i++){    P.Add(NewList(c + 1, 0));}for (i = 1; i <= r; i++){    row = Console.ReadNumbers();    for (j = 1; j <= c; j++)    {        P[i][j] = row[j - 1] + P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1];    }} for (k = 0; k < q; k++){    qq = Console.ReadNumbers();    r1 = qq[0];    c1 = qq[1];    r2 = qq[2];    c2 = qq[3];    Console.WriteLine(P[r2][c2] - P[r1 - 1][c2] - P[r2][c1 - 1] + P[r1 - 1][c1 - 1]);}