差分数组+两个简单例子

目录

1.什么是差分数组?

2.差分数组怎么求

差分数组能干啥

差分数组怎么用:

例1:HDU-1556 Color the Ball  Problem - 1556

例2:   1109. 航班预订统计

3.差分数组的性质:


参考链接:前缀和以及差分 - ycloong - 博客园

1.什么是差分数组?

从字面上解释,差分数组就是记录一个数组的前后元素之差的数组,例如:

有数组nums的内容如下:

0	1	2	3	4	5
2	4	1	5	8	10

那么数组nums的差分数组diff就是:

        0	1	2	3	4	5
nums	2	4	1	5	8	10
diff	2	2	-3	4	3	2

数组diff的长度和原数组nums一样,其中diff[0]默认为nums[0],其它

diff[i] = nums[i] - nums[i-1]

1.差分数组的特点一:

当我们需要在长度很大的原数组的某个区间做频繁的统一运算操作时,可以不操作原数组,而是直接计算其差分数组以提高效率。举个简单的例子,现在需要将上面数组nums的[1, 3]区间元素都累加2,则结果如下:

        0	1	2	3	4	5
nums	2	4+2	1+2	5+2	8	10
diff	2	2+2	-3	4	3+(-2)	2

所以对原数组某个区间的操作只会影响差分数组中两个元素的值,如果区间是[i,j],那么只会影响差分数组的i和j+1两个元素

2.差分数组的特点二:

d[i] = f[0] + f[1] + … + f[i]

即用差分数组的前i项和可以求得原数组的第i个元素的值!

nums[3] = 7 = diff[0] + diff[1] + diff[2] + diff[3] = 2 + 4 - 3 + 4 = 7

差分其实就是数据之间的差,什么数据的差呢?就是上面所给的原始数组的相邻元素之间的差值,我们令 d[i]=a[i+1]-a[i],一遍for循环即可将差分数组求出来。

下面给你一个栗子,给出一个差分数组先

2.差分数组怎么求

其实差分数组是一个辅助数组,从侧面来表示给定某一数组的变化,一般用来对数组进行区间修改的操作

还是上面那个表里的栗子,我们需要进行以下操作:

1、将区间【1,4】的数值全部加上3

2、将区间【3,5】的数值全部减去5

很简单对吧,你可以进行枚举。但是如果给你的数据量是1e5,操作量1e5,限时1000ms你暴力枚举能莽的过去吗?T到你怀疑人生直接。这时我们就需要使用到差分数组了。

其实当你将原始数组中元素同时加上或者减掉某个数,那么他们的差分数组其实是不会变化的。

利用这个思想,咱们将区间缩小,缩小的例子中的区间 【1,4】吧这是你会发现只有 d[1]和d[5]发生了变化,而d[2],d[3],d[4]却保持着原样,

在进行下一个操作,

这时我们就会发现这样一个规律,当对一个区间进行增减某个值的时候,他的差分数组对应的区间左端点的值会同步变化,而他的右端点的后一个值则会相反地变化,其实这个很好理解

其实也就这么一点代码就ok了

  1. while(m--){//操作次数

  2. cin>>left>>right>>change;//左右端点及其变化的值

  3. d[left]+=change;

  4. d[right+1]-=change;

  5. }

差分数组能干啥

既然我们要对区间进行修改,那么差分数组的作用一定就是求多次进行区间修改后的数组喽

注意 只能是区间元素同时增加或减少相同的数的情况才能用

因为我们的差分数组是由原始数组的相邻两项作差求出来的,即 d[i]=a[i]-a[i-1];那么我们能不能反过来,求得一下修改过后的a[i]呢?

直接反过来即得  a[i]=a[i-1]+d[i] 

事实证明这是正确的,具体证法就不再推广,有空再补上吧;

更新数组a的方式则是下面的那一点点代码,这样我们就求出来了更新后的数组 a,是不是比线段树快多了呢?

  1. for(int i=1;i<=n;i++)

  2. a[i]=a[i-1]+b[i];

差分数组怎么用:

翻来覆去还是那句,区间修改,当然了,有时候要结合树状数组来使用。直接看题目吧

例1:HDU-1556 Color the Ball  Problem - 1556

这个题果的不能再果了吧,看懂上面的,闭着眼也能敲出来

直接附上代码吧

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x3f3f3f3f;
const int mm=1e5+10;
 
int a[mm],b[mm];
int x,y;
int main()
{
    int n;
    while(scanf("%d",&n)&&n){
        mem(a,0);
        mem(b,0);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&x,&y);
            b[x]++;
            b[y+1]--;
        }
        for(int i=1;i<=n;i++)
            a[i]=a[i-1]+b[i];
       
        for(int i=1;i<n;i++)
            printf("%d ",a[i]);
        printf("%d\n",a[n]);
    }
    return 0;
}

例2:   1109. 航班预订统计

在遍历bookings数组的过程中,我们需要对返回的答案数组不断的做区间增量修改,因此可以使用差分数组来求解。

3.差分数组的性质:

当我们希望对原数组的某一个区间[l,r]施加一个增量inc时,差分数组d对应的变化是:d[l]增加inc,d[r+1]减少inc,并且这种操作是可以叠加的。

例如:有数组d=[1,2,3,4,5,6],对d[2]到d[4]之间的所有数加上3,变为d=[1,2,6,7,8,6],那么差分数组也就从[1,1,1,1,1,1]变成了[1,1,4,1,1,-2]。

也就是说,当我们需要对原数组的不同区间施加不同的增量,我们只要按规则修改差分数组即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学生类是一个用于表示学生的抽象概念。通常情况下,学生类包含姓名和分数两个属性,用于描述学生的基本信息。在面向对象程序设计中,学生类还可以包含一些方法,用于处理学生对象的各种操作,比如计算成绩,输出学生信息等。 在创建一个学生类对象时,需要初始化其属性值。一般来说,可以通过构造函数来实现初始化操作。例如: class Student: def __init__(self, name, score): self.name = name self.score = score 这个学生类的构造函数接受两个参数,分别是学生的姓名和分数。在构造函数中,使用self关键字来定义学生对象的属性。即self.name表示学生的姓名属性,self.score表示学生的分数属性。 除了构造函数,学生类还可以定义其他方法,用于实现各种函数。比如,定义一个方法用于计算学生的平均分数: class Student: def __init__(self, name, score): self.name = name self.score = score def calc_average_score(self): total_score = sum(self.score) average_score = total_score / len(self.score) return average_score 在这个例子中,定义了一个名为calc_average_score的方法,用于计算学生的平均分数。这个方法接受一个参数self,表示当前对象实例自身。具体来说,这个方法通过内置函数sum和len来计算学生的总分和平均分,最终返回平均分值。 综上所述,学生类是一个基本的抽象概念,在具体实现时可以根据需要添加属性和方法。在使用学生类时,需要创建对象并初始化属性值,然后通过调用对象的方法来处理各种操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值