二维前缀和

70 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

二维前缀和

  • 在一个矩阵里面,计算子矩阵的和

二维前缀和的计算

  • s(i,j)以i,j为右下角的矩阵的和,a(i,j)为矩阵中的数

  • 如何计算s(i,j)?

    s[i][j] = s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]
    

    计算以(i,j)为右下角的矩阵的前缀和,此时,将s(i-1,j)+s(i,j-1)+a(i,j),此时以(i-1,j-1)的矩阵被减了两次,加上s(i-1,j-1),

    从而求得s(i,j)

  • 如何计算以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的和?

s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]

推导过程:

把以(x2,y2)的右下角的矩阵的和减去以(x1-1,y2)为右下角的矩阵的,减去以(x2,y1-1)为右下角的矩阵,此时,以(x1-1,y1-1)为右下角的矩阵被减了两次,此时需要加上一次,+s(x1-1)(y1-1)

例题

输入一个 nm 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2

,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式

第一行包含三个整数 nmq

接下来 n行,每行包含 m个整数,表示整数矩阵。

接下来 q 行,每行包含四个整数 x1,y1,x2,y2,表示一组询问。

输出格式

q行,每行输出一个询问的结果。

数据范围

1≤n,m≤1000, 1≤q≤200000, 1≤x1≤x2≤n, 1≤y1≤y2≤m, −1000≤矩阵内元素的值≤1000

输入样例:

3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4

输出样例:

17
27
21

代码

package main
​
import "fmt"
​
var (
    n int
    m int
    q int
    a [1010][1010]int
    s [1010][1010]int
)
​
func main() {
    fmt.Scanf("%d %d %d", &n, &m, &q)
    for i := 1; i <= n; i++ {
        for j := 1; j <= m; j++ {
            fmt.Scanf("%d", &a[i][j])
        }
    }
    for i := 1; i <= n; i++ {
        for j := 1; j <= m; j++ {
            s[i][j] = s[i-1][j] + s[i][j-1] + a[i][j] - s[i-1][j-1]
        }
    }
    var x1, y1, x2, y2 int
    for i := 0; i < q; i++ {
        fmt.Scanf("%d %d %d %d", &x1, &y1, &x2, &y2)
        ans := s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1]
        fmt.Println(ans)
    }
}