[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

例题如下:

posted @ 2020-11-01 18:28  herrhu  阅读(108)  评论(0)    收藏  举报