差分(入门)

一:定义

差分可以看作前缀和的逆运算,不会可以来这里看看

二:作用

可以在O(1)的时间内的进行很多连续的数的加减操作

三:一维差分

1.关系

我们现在有一个数组a,还有它的前缀和数组sum

那么数组a就是它的前缀和数组sum的差分数组

也就是说,一个数组的差分数组只要经过一次前缀和操作就成了原数组

2.构造

现在我们知道了一维差分数组和原数组之间的关系

那我们就可以假定d数组是a数组的差分数组

那么,问题来了,怎么构造d数组呢?

多想亿想我们就能发现

d[i] = a[i]-a[i-1]

所以d数组就可以等于

#include<bits/stdc++.h>
using namespace std;
int a[114514];
int d[114514];//a的差分数组
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)d[i] = a[i]-a[i-1];
    return 0;
}

3.操作

现在我们已经构建好了d数组,那我们怎么能让它进行大规模的加减操作呢?

因为a是d的前缀和数组,所以要想在最后把d还原,就要对d进行前缀和操作

那么,如果把d[i]加一个数,那么还原后一定会影响其后的所有数字

所以,我们不仅要在开始点+x(x为增加的数),还要在它的结束点的后一个点-x 

这样就不会影响到之后的数了

那么代码就是

int x,y,z;//x 表示左节点,y表示右节点,z表示增加的数
cin>>x>>y>>z;
a[x] += z;
a[y+1] -= z;

四:二维差分

1.关系

同一维差分,当a是d的前缀和数组时,d是a的差分数组

2.构造和操作

因为二维的差分数组不好构造,所以,我们可以在输入时就进行操作

我们可以先假装a数组的数为0,

那么d数组就肯定全是0

然后我们在把输入a当作往d数组进行增加操作

那么,当我们输入完a数组的数字,d就自然成为了a的差分数组

那怎么操作呢?

我们可以类比二维前缀和来理解

如果x1,y1代表左上坐标,x2,y2 代表右下坐标

那么如果只把d[x1][y1]增加肯定不行


因为我们要是直接把d[x1][y1]增加的话,那么从(x1,y1)到后面的内容都会增加,

所以我们要让多余部分d[x2+1][y1]和d[x1][y2+1]减少

同时,因为d[x2+1][y1]和d[x1][y2+1]减少,所以d[x2+1][y2+1]后的内容会减两遍

那么还要把d[x2+1][y2+1]增加

所以增加的部分的代码就是

int x1,y1,x2,y2,z;//z为增加的量
cin>>x1>>y1>>x2>>y2>>z;
d[x1][y1] += z;
d[x2 + 1][y1] -= z;
d[x1][y2 + 1] -= z; 
d[x2 + 1][y2 + 1] += z;

3.注意

另外,在构建时,如果输入a[i][j]

那么x1和x2都是i,y1和y2都是j

五:结语

如果本文对您有帮助的话,别忘记点赞收藏加关注支持一下吖~

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值