Noip 2012 借教室 (二分答案+差分数组)

题面

题目链接

思路

朴素的想法我们回去暴力修改区间元素,从而判断教室能否够用,但是看数据范围显然这会超时,既然区间问题我们立马想到前缀和和差分数组,and线段树和树状数组,这里不写树状数组和线段树的做法。我们看数据测试量,然后看了一下,这个答案具有线性性质,所以我们可以二分加速,所以我们二分mid,去找不满足条件的最右点,然后在check里面,我们维护一个差分数组,来保存我们要存的教室的数量,最后累加一次前缀和,发现有元素大于原有教室个数,那么我们就判定这个条件下是行不通的。

代码实现

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include<vector>
#include <functional>
#define x first
#define y second 
using namespace std;
typedef long long ll;
const int maxn=1000005;
int r[maxn],s[maxn],e[maxn],d[maxn],l,ri,cf[maxn],need[maxn];
int n,m;
bool check (int mid) {
    memset (cf,0,sizeof (cf));
    for (int i=1;i<=mid;i++) {
      cf[s[i]]+=d[i];
      cf[e[i]+1]-=d[i];
    }
    for (int i=1;i<=n;i++) {
        need[i]=need[i-1]+cf[i];
        if (need[i]>r[i]) return 0; 
    }
    return 1;
}
int main () {
    cin>>n>>m;
    for (int i=1;i<=n;i++) cin>>r[i];
    for (int i=1;i<=m;i++) {
       cin>>d[i]>>s[i]>>e[i];
    }
    l=1,ri=m;
    if (check(m)) {
     cout<<0<<endl;
     return 0;
    }
    while (l<ri) {
       int mid=(l+ri)/2;
       if (check(mid)) {
           l=mid+1;
       }
       else ri=mid;
    }
    cout<<-1<<endl<<l;
    return 0;
}

原文地址:https://www.cnblogs.com/hhlya/p/13193922.html