前缀和&差分

前缀和子矩阵:

#include <iostream>
using namespace std;
const int N = 1010;
int a[N][N],s[N][N];
int main()
{
    int n,m,k;
    cin>>n>>m>>k;
    for(int i = 1;i<=n;i++)
        for(int j = 1;j<=m;j++)
        {
            cin>>a[i][j];
            s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
        }
    while(k--)
    {
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        int t = s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1];
        cout<<t<<endl;
    }

    return 0;
}
s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
差分:
#include <iostream>
using namespace std;
const int N = 100010;
int a[N],b[N];
void insert(int l, int r, int c)
{
    b[l] += c;
    b[r+1] -= c;
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i = 1;i<=n;i++)
        cin>>a[i];
    for(int i = 1;i<=n;i++) insert(i, i, a[i]);
    while(m--)
    {
        int l,r,c;
        cin>>l>>r>>c;
        insert(l, r, c);
    }
    for (int i = 1; i<=n; i++)
        a[i] = a[i-1] + b[i];
    for(int i = 1;i<n;i++)
        cout<<a[i]<<" ";
    cout<<a[n]<<endl;
    
    return 0;
}

构造差分数组:a[i] = b[1] + b[2] + ... + b[i];

那么如何通过已知的a数组来得出b数组呢?通过insert(i,i,a[i]); b[l] += c; b[r+1] -= c;

可以模拟一下,比如

b[1] = b[1] + a[1] = a[1]; b[2] = -a[1];

b[2] = b[2] + a[2] = -a[1] + a[2];---> a[2] = a[1] + b[2] = b[1] + b[2] ; b[3] = -a[2];

b[3] = -a[2] + a[3]; ---> a[3] = a[2] + b[3] = b[1] + b[2] + b[3] ;b[4] = -a[3];

非常巧妙。

由a数组得到差分数组b之后,就可以通过前缀和,a[n] = a[n-1] + b[n];来输出a[n]即可。

同理二维差分矩阵,可以类似于从一维差分和前缀和子矩阵两种结合起来得到:

#include <iostream>
using namespace std;
const int N = 1010;
int a[N][N],b[N][N];
void insert(int x1,int y1, int x2, int y2, int c)
{
    b[x1][y1] += c;
    b[x2+1][y1] -= c;
    b[x1][y2+1] -= c;
    b[x2+1][y2+1] += c;
}
int main()
{
    int n,m,k;
    cin>>n>>m>>k;
    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++)
            insert(i,j,i,j,a[i][j]);
    while(k--)
    {
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        insert(x1,y1,x2,y2,c);
    }
    for (int i = 1; i<=n; i++)
        for(int j = 1;j<=m;j++)
            a[i][j] = a[i-1][j]+a[i][j-1] - a[i-1][j-1] + b[i][j];
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++)
            cout<<a[i][j]<<" ";
        cout<<endl;
    }
    
    return 0;
}

 同样可以模拟一下:

b[1][1] = a[1][1];b[1][2] = -a[1][1] = -b[1][1], b[2][1] = -b[1][1];b[2][2] = a[1][1] = b[1][1];

b[1][2] = -b[1][1] + a[1][2], --->a[1][2] = b[1][1] + b[1][2], b[2][2] = -a[1][2]...

b[2][1] = -b[1][1] + a[2][1],--->a[2][1] = b[1][1] + b[2][1], b[2][2] = -a[2][1]...

b[2][2] = -a[1][2] - a[2][1] + b[1][1] + a[2][2],--->a[2][2] = a[1][2] + a[2][1] - b[1][1] = b[1][1] + b[1][2] + b[1][1] + b[2][1] - b[1][1] + b[2][2] = b[1][1] + b[1][2] + b[2][1] + b[2][2];

可以看到这样就可以得到a数组是b数组的前缀二维子矩阵和了。

 
原文地址:https://www.cnblogs.com/longxue1991/p/12650773.html