[NOIp2012] luogu P1083 借教室

该*的英语,这么长还要背。

题目描述

你有 nn 个数 ai{a_i}mm 次操作,每次操作将 [l,r][l,r] 区间的每个数减去 cc。要求任何时刻 x[1,n]\forall x\in[1,n] 都有 ai0a_i\geq0,请你告诉我最多可以合法地执行多少次操作。

Solution

很明显这是个差分数组对吧。

二分答案即可,每次线性地判断该状态是否合法。时间复杂度 O(nlogm)O(n\log m)

#include<cstdio>
#include<cstdlib>
#include<cstring>

const int MAXN=1000010;

int n,m;
int d[MAXN],D[MAXN];
int sx[MAXN],sy[MAXN],sd[MAXN];

int check(int x){
	for(int i=1;i<=n;++i)
		d[i]=D[i];
	for(int i=1;i<=x;++i){
		d[sx[i]]-=sd[i];
		d[sy[i]+1]+=sd[i];
	}
//	printf("%d\t",x);
//	for(int i=1;i<=n;++i)
//		printf("%d ",d[i]);
//	puts("");
	int tmp=0;
	for(int i=1;i<=n;++i){
		tmp+=d[i];
		if(tmp<0) return 0;
	}
	return 1;
}
inline int read(){
	int x=0; char c;
	do c=getchar(); while(c<'0'||c>'9');
	while(c>='0'&&c<='9')
		x=x*10+c-48,c=getchar();
	return x;
}
int main(){
	n=read();m=read();d[0]=0;
	for(int i=1;i<=n;++i){
		d[i]=read();
		D[i]=d[i]-d[i-1];
	}
	for(int i=1;i<=m;++i){
		sd[i]=read();
		sx[i]=read();
		sy[i]=read();
	}
	int l=0,r=n,mid,ans=-1;
	while(l<=r){
		mid=(l+r)/2;
		if(check(mid)){
			ans=mid;
			l=mid+1;
		}
		else
			r=mid-1;
	}
	puts(ans==n?"0":"-1");
	if(ans!=n) printf("%d",ans+1);
}
posted @ 2019-09-12 15:28  TeacherDai  阅读(120)  评论(0)    收藏  举报