二维前缀和

2021-10-23 常用算法 前缀和

# 一、算法思想

相比于 一维前缀和,二维前缀和要解决的问题是快速计算一个矩阵中任意子矩阵的和。

# 1.1 计算方法

Si,j=Si1,j+Si,j1Si1,j1+ai,jS_{i,j}=S_{i-1,j}+S_{i,j-1}-S_{i-1,j-1}+a_{i,j}

# 1.2 作用

O(1)O(1) 时间内计算左上角坐标 (x1,y1)(x_1,y_1)、右下角坐标 (x2,y2)(x_2,y_2) 的子矩阵面积:

S=Sx2,y2Sx2,y11Sx11,y2+Sx11,y11S=S_{x_2,y_2}-S_{x2,y_1-1}-S_{x_1-1,y_2}+S_{x_1-1,y_1-1}

# 二、算法模板

Go

type PrefixSum2D struct {
    sum [][]int
}

// NewPrefixSum2D 初始化二维前缀和
func NewPrefixSum2D(q [][]int) *PrefixSum2D {
    n, m := len(q), len(q[0])
    sum := make([][]int, n+1)
    for i := range sum {
        sum[i] = make([]int, m+1)
    }
    for i := 1; i <= n; i++ {
        for j := 1; j <= m; j++ {
            sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + q[i-1][j-1]
        }
    }
    return &PrefixSum2D{sum: sum}
}

// 查询二维前缀和
func (ps *PrefixSum2D) query(x1, y1, x2, y2 int) int {
    return ps.sum[x2][y2] - ps.sum[x2][y1-1] - ps.sum[x1-1][y2] + ps.sum[x1-1][y1-1]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 三、代码实战

# AcWing 0796


题目:子矩阵的和

输入一个 nnmm 列的整数矩阵,再输入 qq 个询问,每个询问包含四个整数 x1,y1,x2,y2x_1,y_1,x_2,y_2,表示一个子矩阵的左上角坐标和右下角坐标。

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

输入格式

第一行包含三个整数 nnmmqq

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

接下来 qq 行,每行包含四个整数 x1,y1,x2,y2x_1,y_1,x_2,y_2,表示一组询问。

输出格式

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

数据范围

1n,m10001 \le n,m \le 1000
1q2×1051 \le q \le 2 \times 10^5
1x1x2n1 \le x_1 \le x_2 \le n
1y1y2m1 \le y_1 \le y_2 \le m
1000矩阵内元素的值1000-1000 \le \text{矩阵内元素的值} \le 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

解答代码:

    Last Updated: 2023-01-28 4:31:25