[AcWing]前缀和差分
前缀和
前缀和本身是一种思想,用来解决一个确定区间的和的问题,如[l,r];
它能将本身o[n]复杂度的情况变成o[1],基本公式如下
//一维前缀和
s[n] = a[1] + a[2] + a[3] + a[4] + ... + a[n]
a[l] + a[l + 1] + ... + a[r] = s[r] - s[l - 1]
//二维前缀和
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
例题如下:

#include<iostream>
using namespace std;
const int N = 1010; //不能写成100010,内存存不下
int n, m, q;
int a[N][N], s[N][N];
int main()
{
    cin >> n >> m >> q;
    
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            cin >> a[i][j];
    
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            s[i][j] = s[i - 1][j] + s[i][j - 1] + a[i][j] - s[i - 1][j - 1];
            
    while(q--)
    {
        int x1,y1,x2,y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;
    }
    
    return 0;
}
差分
差分相当于是前缀和的逆运算,适用于对一个区间内的数加上一个数,将本来复杂度位n的变成1
先构建原序列的差分序列,在[l,r]这个范围内,为了将数加上c,在差分序列中将l处的值加c,r+1处的值减c
//差分
给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c
//差分矩阵
给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c
例题如下:


 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号