目录

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

差分

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

思想

给定我们一个数组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;
}
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
Ludicrouers2 小时前
【Leetcode-Hot100】和为k的子数组
算法·leetcode·职场和发展
巨可爱熊2 小时前
高并发内存池(定长内存池基础)
linux·运维·服务器·c++·算法
爱数模的小驴4 小时前
2025 年“认证杯”数学中国数学建模网络挑战赛 C题 化工厂生产流程的预测和控制
深度学习·算法·计算机视觉
码农新猿类5 小时前
服务器本地搭建
linux·网络·c++
Hanson Huang5 小时前
【数据结构】堆排序详细图解
java·数据结构·排序算法·堆排序
Susea&5 小时前
数据结构初阶:队列
c语言·开发语言·数据结构
GOTXX5 小时前
【Qt】Qt Creator开发基础:项目创建、界面解析与核心概念入门
开发语言·数据库·c++·qt·图形渲染·图形化界面·qt新手入门
徐行1106 小时前
C++核心机制-this 指针传递与内存布局分析
开发语言·c++
序属秋秋秋6 小时前
算法基础_数据结构【单链表 + 双链表 + 栈 + 队列 + 单调栈 + 单调队列】
c语言·数据结构·c++·算法
apcipot_rain7 小时前
【密码学——基础理论与应用】李子臣编著 第五章 序列密码 课后习题
算法·密码学