luogu P1083 借教室

二次联通门 : luogu P1083 借教室

 

 

 

/*    
    luogu P1083 借教室 
    
    
    二分 + 前缀和 + 贪心 
    
    其实一看这个题我是想用线段树去做的....
    根本看不出从哪里要二分..
    
    思路:
        二分一下订单的编号
        检查答案是否可行, 可行就向后找 , 否则就向前找..
        
        前缀和是第 i 天需要的教室数 
        具体检查过程   做一下前缀和
            比如 l~r 天要x个教室
            那么 sum[l] += x
                 sum[r + 1] -= x
                这样的话就处理出了第i天要借的教室数
                最后加起来看看是否超过原有的教室即可 
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#define Max 1000209

using namespace std;

void read (int &now)
{
    now = 0;
    char word = getchar ();
    while (word < '0' || word > '9')
        word = getchar ();
    while (word >= '0' && word <= '9')
    {
        now = now * 10 + word - '0';
        word = getchar ();
    }
}
int N;
int M;
int sum[Max];
int number[Max];
int Answer;
struct Ruri
{
    int number;
    int start;
    int end;
}res[Max];
bool Check (int day)
{
    memset (sum, 0, sizeof (sum));
    int now = 0;
    for (int i = 1; i <= day; i++)
    {
        sum[res[i].start] += res[i].number;
        sum[res[i].end + 1] -= res[i].number;
    }
    for (int i = 1; i <= N; i++)
    {
        now += sum[i];
        if (now > number[i])
            return false;
    }
    return true;
}
int main (int argc, char *argv[])
{
    read (N);
    read (M);
    for (int i = 1; i <= N; i++)
        read (number[i]);
    for (int i = 1; i <= M; i++)
    {
        read (res[i].number);
        read (res[i].start);
        read (res[i].end);
    }
    int l = 1;
    int r = M;
    int Mid;
    while (l <= r)
    {
        Mid = (l + r) >> 1;
        if (Check (Mid))
            l = Mid + 1;
        else 
        {
            Answer = Mid;
            r = Mid - 1;
        }
    }
    if (!Answer)
        putchar ('0');
    else 
        printf ("-1\n%d", Answer);
    return 0;
}

 

posted @ 2017-05-20 20:56  ZlycerQan  阅读(220)  评论(0编辑  收藏  举报