【前缀和+差分思想】+题目(It Rains Again)讲解

其中用到的S数组存的是前缀和的值即某区间的总和,a数组代表的该点的数值

一维前缀和:适用于频繁的查询某区间的和

用途:求某一区间的和

eg:求3~9区间的和:s[9]-s[3]

 二维前缀和:适用于求某一矩形的面积

首先给前缀和数组赋值:

放到坐标上:求出前缀和

 求某一矩形面积:(给出两点:我举例的是(i,j)和(i-1,j-1)组成的矩形面积)

 推广到坐标上:

 差分数组

其实就可以理解为原数组a;  例如:我求的a[i]=s[i]-s[i-1];

用途:频繁对某一区间进行加值,求某个数的值;

做法:只需要对某区间的端点进行标记,既可以算出某点被覆盖(加/操作)了几次;

具体 的思想我想大概可以用这道题(It Rains Again)来很好的解释!!look!


好啦~,在了解什么是前缀和以及差分数组来让我们一起看看这道(It Rains Again)题趴~

 题目:(It Rains Again)

总结题目意思:

给你一些区间,这些区间是有伞遮挡的不会被淋湿,让你求不被雨淋到的区间长度是多少?

样例图:

 题解:

其实可以发现这里和纵坐标无关,主要看横坐标覆盖的长度是多少;

处理后:

我通过标记左端点加1,右端点减1的方式(可以理解为我加了一,过了这个区间我就要还原回去所以减一)目的是为了标记几处区间被标记了,拓展开来,这样我也可以知道该点被覆盖过几次;

如果然后求和,如果该处为零则说明未覆盖,反则,有雨伞遮挡,把数记下来即可;

代码

#include <bits/stdc++.h>
using namespace std;
int a[100010],s[100010];
int main()
{
   int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int l,r,x;
        cin>>l>>x>>r>>x;
        a[l]++;;a[r]--;
    }//对区间进行标记;
    for(int i=1;i<=100000;i++)
    {
        s[i]=s[i-1]+a[i];
    }//求出每个点被标记的次数,0则未被标记
    int cnt=0;
    for(int i=0;i<=100000;i++)
    {
        if(s[i])
            cnt++;
    }//计数,看有多少被标记了,也可以用总数减去未被标记的数(0);
    cout<<cnt<<endl;
}

总结:

为什么要用前缀和或者差分的思想呢?本质上是为了减少复杂度;

比如给出m个区间(l,r)对他们进行加一操作,求出操作之后1-n点的数

如果平常来算,我首先要对m个操作进行循环,每次循环都是l-r的长度,那复杂度是(m*(r-l)),r-l最坏的情况可能是n,最后输出n个点的数复杂度为n,所以说复杂度是m*n+n;即o(m*n)

然,如果用差分的思想,我每次只需要要对m个操作进行循环,每次循环都是标记l,r两个点,那复杂度是m*2,最后输出n个点的数复杂度为n,所以说复杂度是m*2+n,即o(n);

将复杂度接近n方降到了n次,解决了超时的问题!!

做完了,还可以看看这道题:送分了QAQ


鱼儿不易~,佬~,点个赞赞撒!谢谢你(^U^)ノ~YO~

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值