[Noip 2012] 借教室

题面

 

    我们二分一下答案,看哪个是最后一个可以被满足的条件。

    每次二分得到mid之后,我们就把1~mid的条件用差分实现区间加,再把这个差分数组前缀和一下得到每个位置需要的教室数,判断一下就可以了。

 

    这里我加了一个小优化,每次修改差分数组都从上一次修改到的点开始修改(即吧差分数组的信息由 1~mid' 改为 1~mid),这样可以证明总的修改差分数组的时间是 O(M) 的。

    复杂度于是从 O( (N+M) * log M ) 降至 O( M + N*log M),再加之二分里那个O(N)的复杂度的常数要比原来没优化之前的O(M)的小得多(会提前返回0的情况),实测快了4倍不止。

(注:图上的那个07-27是前年做的。。。。)

 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5;

inline int read(){
    int x=0; char ch=getchar();
    for(;!isdigit(ch);ch=getchar());
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}

int n,d[N],s[N],t[N];
int r[N],m,R,L,mid,ans,pre;
ll ad[N],now;

inline bool can(){
	now=0;
	if(mid>pre) for(int i=pre+1;i<=mid;i++) ad[s[i]]+=(ll)d[i],ad[t[i]]-=(ll)d[i];
	else for(int i=pre;i>mid;i--) ad[s[i]]-=(ll)d[i],ad[t[i]]+=(ll)d[i];
	
	for(int i=0;i<=n;i++,now+=ad[i]) if(now>r[i]) return 0;
	return 1; 
}

int main(){
	n=read(),R=m=read(),L=1;
	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()+1;
	
	for(;L<=R;pre=mid){
		mid=L+R>>1;
		if(can()) ans=mid,L=mid+1;
		else R=mid-1;
	}
	
	if(ans==m) puts("0");
	else printf("-1\n%d\n",ans+1);
	
	return 0;
}

  

posted @ 2019-08-01 17:12  蒟蒻JHY  阅读(102)  评论(0编辑  收藏  举报