订单的编号具有单调性,也就是说可以往二分答案的方向去思考。
已知订单的编号,也就是说在此订单及其之前的订单都能满足。那么如何快速验证订单是否满足就是要解决的问题。
按题中描述以某一天为下标每个订单都有连续几天的租借数量,对于连续区间的加减问题可以联想到差分与前缀和的解法
已知订单的编号,也就是说在此订单及其之前的订单都能满足。那么如何快速验证订单是否满足就是要解决的问题。
按题中描述以某一天为下标每个订单都有连续几天的租借数量,对于连续区间的加减问题可以联想到差分与前缀和的解法
可以将原来教室数量的列表进行差分,然后可以对区间进行快速加减操作。最后再计算一次前缀和转化回来即可。在转化过程中判断是否有教室数量小于0的一天,如果有那么就证明不满足。
还要注意我将r=m+1,是因为将m出区分开来。因为如果r=m的话根据我的二分写法在m出不满足和满足最后l都是m。所以需要向前走一位用于区分。
//订单的编号具有单调性,也就是说可以往二分答案的方向去思考。
//已知订单的编号,也就是说在此订单及其之前的订单都能满足。那么如何快速验证订单是否满足就是要解决的问题。
//按题中描述以某一天为下标每个订单都有连续几天的租借数量,对于连续区间的加减问题可以联想到差分与前缀和的解法
//可以将原来教室数量的列表进行差分,然后可以对区间进行快速加减操作。最后再计算一次前缀和转化回来即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
struct Node{
int d;
int s;
int t;
} node[maxn];
int cls[maxn];
int n, m;
bool yanz(int x) {
int cl[maxn];
//进行差分
for (int i=1;i<=n;i++) {
cl[i] = cls[i]-cls[i-1];
}
//按订单进行区间操作
for (int i=1;i<=x;i++) {
cl[node[i].s] -= node[i].d;
cl[node[i].t+1] += node[i].d;
}
//进行前缀和
for (int i=1;i<=n;i++) {
cl[i] = cl[i]+cl[i-1];
if (cl[i]<0) return false;
}
return true;
}
int main() {
scanf("%d %d", &n, &m);
for (int i=1;i<=n;i++) {
scanf("%d", cls+i);
}
for (int i=1;i<=m;i++) {
scanf("%d %d %d", &node[i].d, &node[i].s, &node[i].t);
}
int l = 1, r = m+1;
while (l < r) {
int mid = (l+r)/2;
if (!yanz(mid)) r = mid;
else l = mid+1;
}
// cout<<yanz(1);
if (l==m+1) {
printf("0");
return 0;
}
printf("-1\n%d", l);
return 0;
}

京公网安备 11010502036488号