前缀和


一维前缀和


一维前缀和可以理解为数组的前 $n$ 项和,通过预处理出前缀和数组,使某段区间的和的查询变为 $O(1)$,是一种重要的优化手段。

前缀和数组的建立方法如下:

#define N 1000
int a[N], prefix[N];
int main() {
	int n; cin >> n;
	for (int i = 1; i <= n; i++) { // 人为从下标 1 开始,处理边界条件 a[0] = 0
		cin >> a[i];
		prefix[i] = prefix[i - 1] + a[i];
	}
}

对于数组 $a[1\dots n]$,区间 $[l,r]$ 的和就是 $\text{prefix}[r]-\text{prefix}[l-1]$.

二维前缀和


二维前缀和定义为从数组左上角到给定的点 $(i,j)$ 包围的矩形内元素的和。

设数组 $a[1\dots n]$,则根据递推可以得到 $\text{prefix}[i][j]=\text{prefix}[i][j-1]+\text{prefix}[i-1][j]-\text{prefix}[i-1][j-1]+a[i][j]$,如图:

QQ_1736512043735.png

故可以得到代码:

#define N 1000
#define M 600
int a[N][M], prefix[N][M];
int main() {
	int n, m; cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
			prefix[i][j] = prefix[i - 1][j] + prefix[i][j - 1] - prefix[i - 1][j - 1] + a[i][j];
		}
	}
}

则从 $(r_1,c_1)$ 到 $(r_2, c_2)$ 的和为

$$ \text{prefix}[r_2][c_2]-\text{prefix}[r_1-1][c_2]-\text{prefix}[r_2][c_1-1]+\text{prefix}[r_1-1][c_1-1] $$

树上前缀和