前缀和与差分
取C数组为修改数组,C[i]表示的是i~n这些元素都加上C[i]这个数
样例:
ADD(1,3,1)
ADD(2,4,4)
ADD(3,7,3)
我们对[L,R]区间进行加value操作,在C[L]处加上value,在C[R+1]处减去value
最后求序列的每个位置变成了多少,只要看一下这个位置上C的前缀和就可以
升级版:对于一个n*m的表格,要求支持操作ADD(x1,y1,x2,y2,a),表示对于以(x1,y1)为左下角,(x2,y2)为右上角的矩形区域,每个元素都加上a。问最后的表格的样子
和一维版的做法类似。
用数组C存修改信息。在C[x1][y1]处加上a,在C[x2+1][y1]和C[x1][y2+1]处减a,在C[x2+1][y2+1]再加上a。
最后(i,k)位置上的数值就是C数组在(i,k)位置的前缀和。
树状数组区间修改单点查询的时候要用!
上述知识点为我在网上dalao博主找的较好的解释!
我自己对用差分对区间操作的理解,我们对[L,R]区间进行加value操作,在C[L]处加上value,在C[R+1]处减去value,因为最后要用c数组的前缀和与原始数组分别相加,所以在C[L]处加上value只对L以后数有影响,在L以后的前缀和都加上了value,因为要求的作用范围是[L,R],所以R以后的前缀和不能产生影响,则应该在C[R+1]处减去value,以与前面加的value相抵消。二维数组同理。
下面是我遇到的例题:
上交大OJ 1002:二哥种花生
Description
二哥在自己的后花园里种了一些花生,也快到了收获的时候了。这片花生地是一个长度为L、宽度为W的矩形,每个单位面积上花生产量都是独立的。他想知道,对于某个指定的区域大小,在这么大的矩形区域内,花生的产量最大会是多少。
Input Format
第1行有2个整数,长度L和宽度W。
第2行至第L+1行,每行有W个整数,分别表示对应的单位面积上的花生产量A( 0≤A<10 )。
第L+2行有2个整数,分别是指定的区域大小的长度a和宽度b。
Output Format
输出一个整数m,表示在指定大小的区域内,花生最大产量为m。
Sample Input
4 5
1 2 3 4 5
6 7 8 0 0
0 9 2 2 3
3 0 0 0 1
3 3
Sample Output
38
样例解释
左上角:38 = (1+2+3) + (6+7+8) + (0+9+2)
数据范围
对于30%的数据: 1≤L,W≤100;
对于100%的数据: 1≤L,W≤1000。
全部区域大小满足:1≤a≤L,1≤b≤W 。
分析:这里就用到前缀和来求解遍历,以防超时!
AC code:
1 #include <iostream> 2 using namespace std; 3 const int maxn = 1000 + 5; 4 int c[maxn][maxn] = {0}; 5 int main() { 6 int L, W; 7 cin >> L >> W; 8 for(int i = 1; i <= L; i++) 9 for(int j = 1; j <= W; j++) { 10 cin >> c[i][j]; 11 c[i][j] = c[i][j] + c[i][j-1] + c[i-1][j] - c[i-1][j-1]; //求前缀和 12 } 13 14 int a, b; 15 long max=0, sum; 16 cin >> a >> b; 17 18 for( int i = 1; i <= L - a + 1; i++) { 19 for(int j = 1; j <= W - b + 1; j++) { 20 sum = c[i+a-1][j+b-1] - c[i-1][j+b-1] - c[i+a-1][j-1] + c[i-1][j-1]; 21 if(sum > max) 22 max = sum; 23 } 24 } 25 cout << max; 26 return 0; 27 }