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

差分

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

思想

给定我们一个数组a0,a1,a2....an

我们做一个数组b0,b1,b2...bn

bi符合bi=ai-ai-1

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

要求在al到ar中的所有数都加上c

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

al以及al到an所有数,都会+c

只需要在br+1-c,br+1以及br+1到bn所有数都会减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;
}
相关推荐
月华路1 小时前
G1 GC 对数组与大对象(Humongous)的处理
java·jvm·算法
我想走路带风1 小时前
LRU和最长前缀和(计算机网络算法)
计算机网络·算法
M78佐菲2 小时前
Linux学习笔记:进程
linux·笔记·学习·算法
ShineWinsu2 小时前
对于C++:C++20中线程、初始化、Lambda与内存视图等特性的解析
c++·c++20
徐小夕3 小时前
表格、文档、甘特、大屏、表单一站打通:pxcharts超级表格4.0正式上线!
前端·算法·github
张张的快乐时光呀!3 小时前
记录使用 MFC 打开文件对话框读取一张图片并做简单的灰度转换算法简单学习过程
c++·mfc
TechLee4 小时前
跨语言加解密总对不上?这个纯 Go 神库让 AES/RSA 与 PHP、Java 100% 互通
java·后端·算法
东华万里5 小时前
第41篇 C++类与对象核心知识梳理:从底层原理到面试实战
开发语言·c++·大学生专区
qq_589666055 小时前
C语言、C++与C#的区别详解
c语言·c++·c#
月华路6 小时前
G1 新生代对象晋升老年代:实现机制与 GC 日志
java·jvm·算法