自己YY出来的方法,时间复杂度为n*m,但实际上并没有这么多,codeVS上最慢的一组有300多ms。
对于每一个订单,在它的左端点加上需要的教室数量,在右端点加1的位置减去需要的教室数量。然后统计前缀和,如果有某个点的前缀和大于了当天教室的数量,那么就有的订单就有问题了,然后从订单编号从小到大统计在订单区间的教室数量,保存恰好不能满足的那个订单;对于之后不满足题意的前缀和,统计订单的最大编号不能超过之前保存的订单标号。
#include<cstdio>
#define MAXN 1000005
using namespace std;
typedef long long LL;
struct T
{
LL d;
int s,t;
}a[MAXN];
int n,m;
LL cl[MAXN];
LL sum[MAXN];
LL t[MAXN];
int maxn;
int pos = 123456789;
int main()
{
//freopen("classroom.in","r",stdin);
//freopen("classroom.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%lld",&cl[i]);
for(int i = 1; i <= m; i++)
{
scanf("%lld%d%d",&a[i].d,&a[i].s,&a[i].t);
if(a[i].t > maxn)
maxn = a[i].t;
t[a[i].s] += a[i].d;
t[a[i].t] += a[i].d;
if(t[a[i].s] > cl[a[i].s]&&pos > i)
{
pos = i;
}
if(t[a[i].t] > cl[a[i].t]&&pos > i)
{
pos = i;
}
sum[a[i].s] += a[i].d;
sum[a[i].t+1] -= a[i].d;
}
for(int i = 1; i <= maxn; i++)
{
sum[i] += sum[i-1];
}
for(int i = 1; i <= n; i++)
{
if(sum[i] > cl[i])//需求超过教室数量
{
int temp = 0;
for(int j = 1; j <= m; j++)//统计在订单区间内的和
{
if(j > pos) break;//不能超过之前订单的最大编号
if(a[j].s <= i&&a[j].t >= i)
temp += a[j].d;
if(temp > cl[i])
{
pos = j;//保存订单的最大编号
break;
}
}
}
}
if(pos == 123456789)
printf("0\n");
else
{
printf("-1\n");
printf("%d\n",pos);
}
return 0;
}