二维差分 怎么构建差分数组 二维前缀和 AcWing 798. 差分矩阵

#include

using namespace std;

const int N=1010;

int a[N][N],b[N][N],s[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,q;
    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++)
            insert(i,j,i,j,a[i][j]);
            
    while(q--)
    {
        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++)
            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+b[i][j];
            
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            cout<<s[i][j]<<" ";
        cout<<endl;
    }
    
    return 0;
}

二维差分

之前以为二维前缀和全是公式,其实公式是有其实际意义的,所以也不全是死记硬背

现在回想一下那个公式,其实自己也是可以现场推导出来的,公式的意思是,s数组表示该点及其左上角所有点的和

给定我们一个矩阵左上角的顶点和右下角的顶点,我们要求这个矩阵内的所有点的和,使用二维前缀和,假设左上角的点的坐标是 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),右下角的坐标是 ( x 2 , y 2 ) (x_2,y_2) (x2,y2),画格子来进行理解即可理解该公式的实际意义

ans=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1],最后加上的部分是被多减了一次,所以补回来

二维差分和一维差分是一样的,还是定义一个插入函数,差分的逆运算是前缀和,对差分数组b数组进行操作,相当于对该点右下角的所有元素都进行了该操作,所以要实现某一个矩阵内的修改,只需要对左上角和右下角的顶点进行修改,但是,会出现有一些部分多减,所以需要在最后加回来,和二维前缀和一样,用画格子来进行理解是最方便的

插入函数如下

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;
}

如何构造差分数组呢

可以首先把a数组看成是空数组,或者说全是0的数组,那么b数组自然就是a数组的差分数组了,然后调用插入函数,相当于在一个一乘一的矩阵上插入a数组的每一个元素,插入完成之后就构建好了b数组

上面这个比较绕,建议是多思考一下

然后就是插入元素,求b数组的前缀和,输出前缀和,前缀和就是修改后的答案数组

你可能感兴趣的:(算法竞赛,#,acwing算法基础,矩阵,算法,数据结构)