其中用到的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~