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