订单的编号具有单调性,也就是说可以往二分答案的方向去思考。
已知订单的编号,也就是说在此订单及其之前的订单都能满足。那么如何快速验证订单是否满足就是要解决的问题。
按题中描述以某一天为下标每个订单都有连续几天的租借数量,对于连续区间的加减问题可以联想到差分与前缀和的解法
已知订单的编号,也就是说在此订单及其之前的订单都能满足。那么如何快速验证订单是否满足就是要解决的问题。
按题中描述以某一天为下标每个订单都有连续几天的租借数量,对于连续区间的加减问题可以联想到差分与前缀和的解法
可以将原来教室数量的列表进行差分,然后可以对区间进行快速加减操作。最后再计算一次前缀和转化回来即可。在转化过程中判断是否有教室数量小于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; }