差分---(小明的彩灯)蓝桥杯真题,差分思想很明确的模板

题目描述

小明拥有 N个彩灯,第 i个彩灯的初始亮度为 ai​。

小明将进行 Q次操作,每次操作可选择一段区间,并使区间内彩灯的亮度 +x(x可能为负数)。

求 Q次操作后每个彩灯的亮度(若彩灯亮度为负数则输出 0)。
​​​​​​​​在这里插入图片描述
输入输出样例
输入

5 3
2 2 2 1 5
1 3 3
4 5 5
1 1 -100

输出

0 5 5 6 10

暴力解法

看见这个题其实第一反应是暴力应该挺好写,确实,思路很明确,就是将[ l , r ]上的数都 “+x”。呢就循环,时间复杂度也是O(n),甚至空间开辟的更少,有一点要注意,数据范围,int是不满足的。

#include<iostream>
using namespace std;
const int n=5*1e5;
long long A[n];
int main()
{
  int N,Q;
  scanf("%d%d",&N,&Q);
  for(int i=1;i<=N;i++)
    scanf("%lld",&A[i]);
  while(Q--)
  {
    long long l,r,x;
    scanf("%lld%lld%lld",&l,&r,&x);
    for(int i=l;i<=r;i++)
      A[i]+=x;
  }
  for(int i=1;i<=N;i++)
  {
    if(A[i]<0) A[i]=0;
    printf("%lld ",A[i]);
  }
  return 0;
}

在这里插入图片描述

差分的思路和模板

差分差分顾名思义,就是把加起来的数,再拆开,研究过前缀和的便知道,差分便是前缀和的逆运算。
一维数组差分
就拿样例的数组 a [2,2,2,1,5],
则它的差分数组 b [2,0,0,-1,4]

假设我们让数组区间[2,4]元素都增加 2
则数组a[2,4,4,3,5]
差分数组b[2,2,0,-1,3]

我们可以发现规律,对于差分数组b,对于任意区间[l,r],“+x” 它的数组变化为b[l]+=x, b[r+1]-=x;
其次为了方便对数据进行差分,通常将数据存放再a[1]的位置,a[0]空为0

呢说到这了,差分要如何存储呢?
这里依然使用,a [2,2,2,1,5]作为模板,我们现在要做的是将其拆为原型

a[i-1]=b[1]+b[2]+b[3]+····+b[i-1]
a[i]=b[1]+b[2]+b[3]+·······+b[i-1]+b[i]
So, b[i]=a[i]-a[i-1]
这里可以开个小差,考考大家
一维前缀和是咋存的呢?
笨蛋,移个项,a[i]=a[i-1]+b[i],记住了吗?嘿嘿

之后很总要的一点,为什么可以利用差分?

上面也有说,对于差分数组b,对于任意区间[l,r],“+x” 它的数组变化为b[l]+=x, b[r+1]-=x,由于,差分又重组,前面加一个元素,其实相当于后面每个元素在求总和时都加了一个元素,超出区间的人家不需要加这个元素,你就再减去,这个适合,数很多的情况,不用一个一个加了

差分解法

#include <iostream>
using namespace std;
const int n=5*1e5;
long long A[n]={0},B[n]={0};
int main()
{
  int N,Q;
  scanf("%d%d",&N,&Q);
  for(int i=1;i<=N;i++)
  {
    scanf("%lld",&A[i]);
    B[i]=A[i]-A[i-1];//差分
    // cout<<B[i];
  }
  while(Q--)
  {
    long long l,r,x;
    scanf("%lld%lld%lld",&l,&r,&x);
    B[l]+=x;
    B[r+1]-=x;//
  }
  for(int i=1;i<=N;i++)
  {
    A[i]=A[i-1]+B[i];
  }
  for(int i=1;i<=N;i++)
  {
    if(A[i]<0) A[i]=0;
    printf("%lld ",A[i]);
  }

  // 请在此输入您的代码
  return 0;
}

在这里插入图片描述
其实,时间消耗差不多,甚至暴力的更好,这个只是差分模板很好的一个题,但是当数据很大很多,还是建议使用差分

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值