前言:具有二分性质,在处理到某个人时,教室数量突然就<0,然后就不能再处理请求了。将处理的订单数作为二分枚举对象依旧是一道二分+验证的题,并且同前缀和与差分结合起来(注意:涉及到对区间大量的+-操作,一定不能直接操作,而是要维护一个差分数组,不然时间直接爆表)
思路&AC代码:
#include<iostream>
#include<cstring>//memcpy()
using namespace std;
int room[1000010];
int delta[1000010];
int tmpd[1000010];
int n;
struct ty
{
int d,s,t;
}deal[1000010];
bool judge(int x)
{
//另一种写法memcpy(tmpd+1,delta+1,n*sizeof(delta[1]));相当于把delta[1]到delta[n]复制到tmpd[1]到tmpd[n];memcpy(复制到的地址,原地址,总字节长度);数组名+1指向数组名[1]元素所在的地址
memcpy(tmpd,delta,sizeof(delta));//sizeof(数组名),等于数组所占总的字节数
//也可循环赋值,因为每次传入的x不同,不能让修改重复了
for(int i=1;i<=x;++i)
{
tmpd[deal[i].s]-=deal[i].d;//差分
tmpd[(deal[i].t)+1]+=deal[i].d;
}
int sum=0;//教室总数最大1e9
for(int i=1;i<=n;++i)
{
sum+=tmpd[i];//前缀和
if(sum<0) {return false;}//小于0说明没空教室了
}
return true;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);
int m;cin>>n>>m;
delta[0]=0;
for(int i=1;i<=n;++i) {cin>>room[i];delta[i]=room[i]-room[i-1];}//delta:第i天房间数减前一天房间数
//也可直接在原数组上差分,节省空间=>room[0]=0;for(int i=n; i>=1; i--) room[i] -= room[i-1];
for(int i=1;i<=m;++i) {cin>>deal[i].d>>deal[i].s>>deal[i].t;}
int l=0,r=m,mid;//最少处理0份订单,最多全处理完
while(l<r)
{
mid=(l+r+1)>>1;//类比于求满足<=x的最后一个
if(judge(mid)) {l=mid;}
else {r=mid-1;}
}
if(l==m) {cout<<0;}
else {cout<<l+1;}//<=x符合要求的最后一个+1就是第一个不符合要求(取不到的)人
//另一种二分写法
/*while(l<r)
{
mid=(l+r)>>1;
if(!judge(mid)) {r=mid;}//取不到的话,第一个取不到的人就是右界,最后退出循环的时候l==r就是第一个取不到的人
else {l=mid+1;}//能取到的话就再往右边试试,第一个取不到的人就是左界,最后退出循环的时候l==r就是第一个取不到的人
}
if(l==m) {cout<<0;}
else {cout<<l;}*/
return 0;
}