洛谷 ~ P1083 ~ 借教室 (差分数组 + 二分)

在这里插入图片描述
在这里插入图片描述

思路

很容易想到暴力的写法,对于一个订单来说,直接从第一天到最后一天都减去d[i]即可,每个订单复杂度为O(n),总的复杂度为O(n*m)明显超时。
可以发现如果前x个订单不符合要求,那么往后一定不符合,这个性质使得我们可以使用二分来求答案。
我们每次二分一个答案,对于当前答案x,我们需要判断前x个订单是否可以符合要求。如果每一个订单都去暴力去减的话,那么依旧会超时。对于区间减法的操作很容易想到用线段树或者树状数组优化。
但是我们对于这个题我们可以发现这个题的查询是在所有的减法操作之后的,所以我们可以用一种更简单的东西去实现,即差分数组 。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
int n, m, r[MAXN], d[MAXN], s[MAXN], t[MAXN], diff[MAXN];
bool check(int m)
{
    memset(diff, 0, sizeof(diff));
    for (int i = 0; i < m; i++)
    {
        diff[s[i]] += d[i];
        diff[t[i] + 1] -= d[i];
    }
    for (int i = 1; i <= n; i++) 
    {
        diff[i] += diff[i - 1];
        if (r[i] < diff[i]) return false;
    }
    return true;
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &r[i]);
    for (int i = 0; i < m; i++) scanf("%d%d%d", &d[i], &s[i], &t[i]);
    int l = 0, r = m;
    while (l < r)
    {
        int m = l + (r - l) / 2;
        if (check(m)) l = m + 1;
        else r = m;
    }
    if (l < m) printf("-1\n%d\n", l);
    else printf("0\n");
    return 0;
}
/*
4 3 
2 5 4 3 
2 1 3 
3 2 4 
4 2 4
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值