前缀和
题目:有 n 个数,并且有 m 次操作,每一次操作要求查询第 x 个数到第 y 个数的和。
前缀和是一种动态规划的思想,假如有数组 a[i] 。
定义 sum[i] 表示从 1 到 a[i] 的和。状态转移方程则是: sum[i] = sum[i-1] + a[i] ; 其中 sum[1] = a[1] ;
这样可以在O(n)的时间计算出整个数组的前缀和。
查询 a[x...y] = sum[y] - sum[x-1] ;
差分
差分:我们定义 f[i] 表示 a[i] 与 a[i-1] 的差, 则f[i] = a[i] - a[i-1] ; 其中 f[1] = a[1];
差分数组有这样一个性质:对差分数组 f 做前缀和即是原始数组 a 。
例如: 数组 a 为 : 5 3 9 2 6
差分数组 f 为: 5 -2 6 -7 4
对差分数组做前缀和 sum: 5 3 9 2 6
这个性质非常重要,说明差分数组 f 可以通过计算前缀和 得出原始数组 a 。
前缀和与差分
题目:有大小为 n 的数组,现在有 m 个指令,第 i 个指令要求将第 xi 个数到第 yi 个数的每个数加上 k,最后求所有数的值。
指令要求将 xi 个数到 yi 个数都加上k,如果我们立即执行这一指令,无疑是暴力算法,而题目要求的是 i 条指令都结束后再查询值,所以我们没必要立即执行指令。
有了差分的知识,我们再来看题目中的指令,指令将一段连续的区间 a[x...y] 都增加 k,这对于差分数组有什么影响呢?
很明显只会影响 f[x] 和 f[y+1] ,中间段的数据的差还是不变的。
所以对于指令a[x..y]都增加 k ,我们可以把其影响记录到差分数组上,也就是 f[x]+=k; f[y+1]-=k;
最后再做一遍前缀和即可得到最终的数据。
时间复杂度是O(n+m)。
题目:https://ac.nowcoder.com/acm/contest/10322/B
二维前缀和
给定一个 n×m 的矩阵 t ,有 T 次询问,每次会给出四个数 a,b,c,d,求以点 (a,b) 为左上角,点 (c,d) 为右下角的矩形的和。
定义 sum[i][j] 表示以 t[1][1] 为左上角,以 t[i][j] 为右下角的矩形的和。
状态转移方程:sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + t[i][j] ;
查询以点 (a,b) 为左上角,点 (c,d) 为右下角的矩形的和: x = sum[c][d] - sum[a-1][d] - sum[c][b-1] + sum[a-1][b-1];