前缀和 一维差分和二维差分 差分&差分矩阵

差分

记录累计差值,相当于输入前缀和数组,计算保留"原数组",差分和前缀和是互逆操作;

思想

给定我们一个数组a[0],a[1],a[2]....a[n]

我们做一个数组b[0],b[1],b[2]...b[n]

b[i]符合b[i]=a[i]-a[i-1]

此时b是a的差分,a是b的前缀和

要求在a[l]到a[r]中的所有数都加上c

因为a是b的前缀和,只需要在b[l]+c

a[l]以及a[l]到a[n]所有数,都会+c

只需要在b[r+1]-c,b[r+1]以及b[r+1]到b[n]所有数都会减c

这里的n指的是数组末尾

一维差分经典题目

活动 - AcWing

代码

cpp 复制代码
#include<iostream>
using namespace std;
int sun[100010],arr[100010],xsun[100010];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>sun[i];//求差分,输入的数组是前缀和数组
        arr[i]=sun[i]-sun[i-1];//求差分数组
    }
    while(m--){
        int l,r,c;
        cin>>l>>r>>c;
        //因为sum是arr的前缀和,只需要在arr[l]+c
        //sun[l]以及sun[l]到sun[n]所有数,都会+c
        //n是数组最后一个下标
        arr[l]+=c;
        //同样,因为因为sum是arr的前缀和,a[r+1]-c
        //sun[r+1]以及sun[r+1]到sun[n]所有数,都会-c
        arr[r+1]-=c;
    }
    for(int i=1;i<=n;i++){
        xsun[i]=arr[i]+xsun[i-1];//输出改变完值的arr的前缀和数组
        cout<<xsun[i]<<' ';
    }
    return 0;
}

二维差分

题目

活动 - AcWing

思路

把给定的数组当做前缀和数组sun读入,读入的同时求sun的差分,或者说原数组

利用求出的差分数组arr,如果要对一个子矩阵添加删除

只需要对arr数组进行操作,就可以在O(1)的复杂度下批量增删sun数组

假设题目要求对x1,y1,x2,y2子矩阵+c

第一步
假设第二步
实际第二步

上图转换成代码

cpp 复制代码
    	//arr[x1][y1]+c
        //则其前缀和数组从[x1][y1]开始每个都+c
        arr[x1][y1]+=c;
        //arr[x2+1][y1]-c,因为只加子矩阵x1,y1,x2,y2
        //所以去掉多加的部分
        arr[x2+1][y1]-=c;
        //这里也是去掉多+的部分
        arr[x1][y2+1]-=c;
        //两次去掉多+的部分过程中
        //有重复删除的部分,把重复删除的部分,添加上一次
        arr[x2+1][y2+1]+=c;

减完之后,我们就可以求arr的二维前缀和xsun

前缀和

然后输出xsun即可

代码

cpp 复制代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int sun[1010][1010],arr[1010][1010],xsun[1010][1010];
int main(){
    int n,m,q;
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&sun[i][j]);//把初始数组当成前缀和数组输入
            //利用前缀和数组计算原数组
            //或者说计算差分数组
            //差分数组通过sun[i][j]减去arr[i][j]+arr[i][j-1]获取
            //arr[i][j]+arr[i][j-1]的值通过sun不断减去获得
            //具体过程和求前缀和加法逻辑一样
            arr[i][j]=sun[i][j]-sun[i-1][j]-sun[i][j-1]+sun[i-1][j-1];
        }
    }
    //q次询问
    while(q--){
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        //arr[x1][y1]+c
        //则其前缀和数组从[x1][y1]开始每个都+c
        arr[x1][y1]+=c;
        //arr[x2+1][y1]-c,因为只加子矩阵x1,y1,x2,y2
        //所以去掉多加的部分
        arr[x2+1][y1]-=c;
        //这里也是去掉多+的部分
        arr[x1][y2+1]-=c;
        //两次去掉多+的部分过程中
        //有重复删除的部分,把重复删除的部分,添加上一次
        arr[x2+1][y2+1]+=c;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            //求arr的二维前缀和
            xsun[i][j]=arr[i][j]+xsun[i-1][j]+xsun[i][j-1]-xsun[i-1][j-1];
            cout<<xsun[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}
相关推荐
闻缺陷则喜何志丹28 分钟前
【SOSDP模板 容斥原理 逆向思考】3757. 有效子序列的数量|分数未知
c++·算法·力扣·容斥原理·sosdp·逆向思考
CoovallyAIHub31 分钟前
如何在手机上轻松识别多种鸟类?我们发现了更简单的秘密……
深度学习·算法·计算机视觉
别动哪条鱼31 分钟前
AVAudioFifo
数据结构·ffmpeg·音视频
第二只羽毛37 分钟前
遵守robots协议的友好爬虫
大数据·爬虫·python·算法·网络爬虫
BestOrNothing_20151 小时前
一篇搞懂 C++ 重载:函数重载 + 运算符重载,从入门到会用(含 ++、<<、== 实战)
c++·函数重载·运算符重载·operator·前置后置++·重载与重写
艾斯比的日常1 小时前
Java 三色标记算法:并发垃圾回收的核心技术解析
java·开发语言·算法
2501_941144421 小时前
Python + C++ 异构微服务设计与优化
c++·python·微服务
CoovallyAIHub1 小时前
抛弃LLM!MIT用纯视觉方法破解ARC难题,性能接近人类水平
深度学习·算法·计算机视觉
程序猿编码1 小时前
PRINCE算法的密码生成器:原理与设计思路(C/C++代码实现)
c语言·网络·c++·算法·安全·prince
高洁011 小时前
具身智能-视觉语言导航(VLN)
深度学习·算法·aigc·transformer·知识图谱