借教室

传送门:https://www.luogu.org/problemnew/show/P1083

先说思路,代码在思路的基础上稍微改了一点,但不难理解。

【差分】维护一个差分数组,对于每一次借教室,单点修改即可。

【二分】如果仅仅用差分来解决此题,会严重超时,所以还需要结合二分来看。先判断从1~(1+m)/2天的人借教室是否合法,如果合法了,再去后半部分继续判断;若不合法,则在前半部找到具体是哪个不合法。

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e6+1;
inline int read()
{
    static char ch;
    while((ch = getchar()) < '0' || ch > '9');
    int ret = ch - 48;
    while((ch = getchar()) >= '0' && ch <= '9')
        ret = ret * 10 + ch - 48;
    return ret;
}
int n,m,r[N],d[N],s[N],t[N],a[N],b[N],ans,ll,rr;
bool check(int mid)
{
    memset(a,0,sizeof(a));
    for(int i = 1;i <= mid;i++)
    {
        a[s[i]] += d[i];
        a[t[i]+1] -= d[i]; 
    }
    for(int i = 1;i <= n;i++)
    {
        b[i] = b[i-1] + a[i];
        if(b[i] > r[i]) return false;
    }
    return true;
}

int main()
{
    n = read();
    m = read();
    for(int i = 1;i <= n;i++) r[i] = read();
    for(int i = 1;i <= m;i++)
        d[i] = read(),s[i] = read(),t[i] = read();
    ll = 1,rr = m,ans = m + 1;
    while(ll <= rr)
    {
        int mid = (ll + rr) >> 1;
        if(check(mid)) ll = mid + 1;
        else 
        {
            rr = mid-1;
            ans = min(ans,mid);
        }
    }
    if(ans == m+1) printf("0");
    else printf("-1
%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/peppa/p/9837969.html