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

差分

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

思想

给定我们一个数组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;
}
相关推荐
随缘而动,随遇而安1 小时前
第八十八篇 大数据中的递归算法:从俄罗斯套娃到分布式计算的奇妙之旅
大数据·数据结构·算法
孞㐑¥1 小时前
Linux之Socket 编程 UDP
linux·服务器·c++·经验分享·笔记·网络协议·udp
IT古董1 小时前
【第二章:机器学习与神经网络概述】03.类算法理论与实践-(3)决策树分类器
神经网络·算法·机器学习
水木兰亭4 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
Jess075 小时前
插入排序的简单介绍
数据结构·算法·排序算法
老一岁5 小时前
选择排序算法详解
数据结构·算法·排序算法
CoderCodingNo5 小时前
【GESP】C++四级考试大纲知识点梳理, (7) 排序算法基本概念
开发语言·c++·排序算法
xindafu5 小时前
代码随想录算法训练营第四十二天|动态规划part9
算法·动态规划
xindafu5 小时前
代码随想录算法训练营第四十五天|动态规划part12
算法·动态规划
freexyn6 小时前
Matlab自学笔记六十一:快速上手解方程
数据结构·笔记·matlab