其实我第一次做借教室是用线段树做的2333。
显然(额),如果你在分配第个订单时就gg了,那么往后的订单就都没法分配了。
那么gg的条件是什么?
设数组表示分配完第个订单后第天还有多少个教室供后来的第个后的订单分配,那么,当数组中出现的情况时,表示第天的教室已经被多个订单分配且无法满足所有的前个订单。这时就gg了。
所以,我们开一棵线段树维护数组的最小值,将订单看作为第个修改操作,将的所有值减去。当修改完后小于0,那么当前的订单就gg了,直接输出-1和即可。若在进行完所有操作后始终,则说明所有订单之间互不冲突,输出0即可。
代码:
#include<cstdio>
#include<iostream>
#define ri register int
using namespace std;
const int MAXN=1000020;
int n,q,a[MAXN],d[MAXN],s[MAXN],t[MAXN];
int l[MAXN<<2],r[MAXN<<2],minn[MAXN<<2],tag[MAXN<<2];
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||'9'<ch) ch=getchar();
while('0'<=ch&&ch<='9')
{
x=(x <<3)+(x <<1)+(ch-'0');
ch=getchar();
}
return x;
}
void pushup(int p)
{
minn[p]=min(minn[p <<1],minn[p <<1|1]);
}
void pushdown(int p)
{
minn[p <<1]-=tag[p],tag[p <<1]+=tag[p];
minn[p <<1|1]-=tag[p],tag[p <<1|1]+=tag[p];
tag[p]=0;
}
void build(int p,int lft,int rit)
{
l[p]=lft,r[p]=rit;
if(l[p]==r[p])
{
minn[p]=a[lft];
return;
}
int mid=(lft+rit)>>1;
build(p <<1,lft,mid);
build(p <<1|1,mid+1,rit);
pushup(p);
}
void update(int p,int lft,int rit,int k)
{
if(lft<=l[p]&&r[p]<=rit)
{
minn[p]-=k;tag[p]+=k;
return;
}
pushdown(p);
if(lft<=r[p <<1]) update(p <<1,lft,rit,k);
if(l[p <<1|1]<=rit) update(p <<1|1,lft,rit,k);
pushup(p);
}
int main()
{
n=read(),q=read();
for(ri i=1;i<=n;i++) a[i]=read();
build(1,1,n);
for(ri i=1;i<=q;i++) d[i]=read(),s[i]=read(),t[i]=read();
for(ri i=1;i<=q;i++)
{
update(1,s[i],t[i],d[i]);
if(minn[1]<0) { cout<<"-1"<<'\n'<<i; return 0; }
}
cout<<"0";
return 0;
}