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

差分

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

思想

给定我们一个数组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;
}
相关推荐
丶小鱼丶7 分钟前
栈算法之【有效括号】
java·算法
linux kernel14 分钟前
第十一讲:模板进阶以及反向迭代器
c++
小徐不徐说3 小时前
每日一算:华为-批萨分配问题
数据结构·c++·算法·leetcode·华为·动态规划·后端开发
姜暮儿5 小时前
C++ 性能优化
开发语言·c++
菜鸟555556 小时前
图论:最小生成树
算法·图论
铭哥的编程日记6 小时前
《从C风格到C++风格:内存管理的进化之路》
开发语言·c++
2401_872945097 小时前
【补题】Codeforces Round 735 (Div. 2) C. Mikasa
算法
叫我:松哥7 小时前
基于网络爬虫的在线医疗咨询数据爬取与医疗服务分析系统,技术采用django+朴素贝叶斯算法+boostrap+echart可视化
人工智能·爬虫·python·算法·django·数据可视化·朴素贝叶斯
Star在努力7 小时前
14-C语言:第14天笔记
c语言·笔记·算法
程序员编程指南7 小时前
Qt 与 SQLite 嵌入式数据库开发
c语言·数据库·c++·qt