题解【洛谷P1083】[NOIP2012]借教室

题面

二分到哪一个申请人要修改订单,可以差分\(+\)前缀和达到\(\Theta(n)\)\(\text{check}\)

具体细节见代码。

#include <bits/stdc++.h>
#define itn int
#define gI gi
#define int long long

using namespace std;

typedef long long ll;

inline int gi()
{
    int f = 1, x = 0; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return f * x;
}

inline ll gl()
{
    ll f = 1, x = 0; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return f * x;
}

const int maxn = 1000003;

int n, m, r[maxn], d[maxn], s[maxn], t[maxn], cf[maxn], sum[maxn], ans = 2000000003;

inline bool check(int mid)
{
    memset(cf, 0, sizeof(cf));//差分数组
    memset(sum, 0, sizeof(sum));//前缀和数组
    for (int i = 1; i <= mid; i+=1) 
    {
        cf[s[i]] += d[i], cf[t[i] + 1] -= d[i];//进行差分
    }
    for (int i = 1; i <= n; i+=1) sum[i] = sum[i - 1] + cf[i];//前缀和计算
    for (int i = 1; i <= n; i+=1) if (sum[i] > r[i]) return true;//当前check的申请人要修改就返回true
    return false;//不要修改
}

signed main()
{
    //freopen(".in", "r", stdin);
    //freopen(".out", "w", stdout);
    n = gi(), m = gi();
    for (int i = 1; i <= n; i+=1) r[i] = gi();
    for (int i = 1; i <= m; i+=1)
        d[i] = gi(), s[i] = gi(), t[i] = gi();
    int l = 1, r = m;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (check(mid)) ans = mid, r = mid - 1;
        else l = mid + 1;
    }
    if (ans == 2000000003) puts("0");
    else printf("-1\n%lld\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xsl19/p/12244221.html
今日推荐