题目链接:
题意:一共有n天,每天可提供Ri个教室,有m份订单,每份订单是从第Si天到第Ji天,借Di个教室,问是否能借完。
分析:一开始想着用线段树,但是线段树在区间更新的时候并不是一个个更新,而是将一整个区间的值改变,对应的点想要查询时再将lazy标记下放,用线段树会非常慢,故不用线段树。
这里有一篇非常好的博客:
在这里提炼下内容:
差分是前缀和数组的逆运算
前缀和是用元数据求元与元之间的并集关系,而差分则是根据元与元之间的逻辑关系求元数据,是互逆思想
是否能二分的界定标准是:状态的决策过程或者序列是否满足单调性或者可以局部舍弃性。 而在这个题里,因为如果前一份订单都不满足,那么之后的所有订单都不用继续考虑;而如果后一份订单都满足,那么之前的所有订单一定都可以满足,符合局部舍弃性,所以可以二分订单数量。(不太好懂,看代码就能理解)
注意:need数组是独立于rest数组的,diff数组是服务于need数组的,diff[i]数组是need[i]-need[i-1],我们利用差分方便的进行修改,最后求出need数组与rest数组做比较(不要轻易相减以防出现re)
#includeusing namespace std;typedef long long ll;const int inf=0x3f3f3f3f;//这个数是1e9数量级的,且可以用memset函数 const int maxn=1e6+7;const double pi=acos(-1);const int mod=1e9+7;int rest[maxn],d[maxn],l[maxn],r[maxn],diff[maxn],need[maxn];int n,m;bool isok(int x){ //用来判断前x份订单需不需要进行修改 memset(diff,0,sizeof(diff)); for(int i=1;i<=x;i++){ diff[l[i]]+=d[i]; diff[r[i]+1]-=d[i]; } for(int i=1;i<=n;i++){ need[i]=need[i-1]+diff[i]; if(need[i]>rest[i]){ return 0; } } return 1;}int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ scanf("%d",&rest[i]); } for(int i=1;i<=m;i++){ scanf("%d%d%d",&d[i],&l[i],&r[i]); } if(isok(m)){cout<<0<