首页 > 代码库 > noip2012借教室

noip2012借教室

Description

技术分享

Input

技术分享


Output

技术分享


Sample Input

4 3
2 5 4 3
2 1 3
3 2 4
4 2 4

Sample Output

-1
2

Data Constraint

Hint

第一份订单满足后,4天剩余教室分数分别为0,3,2,3. 第二份订单要求第二天到第四天每天提供三个教室,而第三天剩余的教室数为二,因此无法满足。分配停止通知第二个申请人修改订单。


10% -> 1<=n,m<=10


30% -> 1<=n,m<=1000


70% -> 1<=n,m<=100000


100% -> 1<=n,m<=1000000, 0<=ri,dj<=1000000000, 1<=sj<=tj<=n


这道题很明显可以用线段树。

然而区间修改有比它更快,更好写的离线方法,差分数组。

首先这道题需要二分答案,接着用差分数组写check函数。b[i]=a[i]-a[i-1];b[1]=a[1];b为差分数组

我们可以发现一个性质(此处不做证明)对与a[i]的[l,r]区间减少s

相当与在b[l]-s,b[r+1]+s;

check(x)时,先求出b,然后进行修改,在之后判断修改过后的b数组根据a[i]=b[i]+a[i-1]判断a[i]<0即可返回false

#include<cstdio>
const int N=1e6+5;
int x[N],y[N],z[N],l[N],r[N],sl[N],n,m;
bool f(int a)
{
    for(int i=1;i<=n;i++) y[i]=x[i]-x[i-1];
    for(int i=1;i<=a;i++) y[l[i]]-=sl[i],y[r[i]+1]+=sl[i];
    for(int i=1;i<=n;i++)
    {
        z[i]=z[i-1]+y[i];
        if(z[i]<0) return 0;
    }
    return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&x[i]);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&sl[i],&l[i],&r[i]);
    int l=0,r=m+1;
    while(l<r-1)
    {
        int mid=(l+r)>>1;
        if(f(mid)) l=mid;
        else r=mid;
    }
    if(r==m+1) putchar(0);
    else printf("-1\n%d",r);
    return 0;
}

 

noip2012借教室