zoukankan      html  css  js  c++  java
  • [vijos1782][NOIP2012]借教室

    Description

    在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。
    面对海量租借教室的信息,我们自然希望编程解决这个问题。我们需要处理接下来\(n\)天的借教室信息,其中第\(i\)天学校有\(r_i\)个教室可供租借。共有\(m\)份订单,每份订单用三个正整数描述,分别为\(d_j,s_j,t_j\),表示某租借者需要从第\(s_j\)天到第\(t_j\)天租借教室(包括第\(s_j\)天和第\(t_j\)天),每天需要租借\(d_j\)个教室。
    我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供\(d_j\)个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。
    借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第\(s_j\)天到第\(t_j\)天中有至少一天剩余的教室数量不足\(d_j\)个。
    现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。

    HINT

    \(1≤n,m≤10^6,0≤r_i,d_j≤10^9,1≤s_j≤t_j≤n\).

    Solution

    简单粗暴做法

    线段树维护区间最大值.

    #define N 1000005
    #define M 3000005
    typedef long long ll;
    struct SegTree{
    	int m,d;
    }lt[M];
    int a[N],n,m;
    inline void build(int u,int ll,int rr){
    	if(ll<rr){
    		int lef=u<<1,rig=u<<1|1,mid=ll+rr>>1;
    		build(lef,ll,mid);build(rig,mid+1,rr);
    		lt[u].m=min(lt[lef].m,lt[rig].m);
    	}
    	else lt[u].m=a[ll];
    }
    inline bool add(int u,int ll,int rr,int l,int r,int k){
    	if(ll>=l&&rr<=r){
    		lt[u].d+=k;lt[u].m-=k;
    		return lt[u].m>=0;
    	}
    	if(ll<rr){
    		int lef=u<<1,rig=u<<1|1,mid=ll+rr>>1;
    		lt[lef].d+=lt[u].d;lt[lef].m-=lt[u].d;
    		lt[rig].d+=lt[u].d;lt[rig].m-=lt[u].d;
    		lt[u].d=0;
    		if(l<=mid) add(lef,ll,mid,l,r,k);
    		if(r>mid) add(rig,mid+1,rr,l,r,k);
    		lt[u].m=min(lt[lef].m,lt[rig].m);
    		return lt[u].m>=0;
    	}
    }
    inline void Aireen(){
    	n=read();m=read();
    	for(int i=1;i<=n;++i)
    		a[i]=read();
    	build(1,1,n);
    	for(int i=1,l,r,k;i<=m;++i){
    		k=read();l=read();r=read();
    		if(!add(1,1,n,l,r,k)){
    			printf("-1\n%d\n",i);
    			return;
    		}
    	}
    	puts("0");
    }
    

    这才是正解

    • 单调性:如果前\(i\)天合法,则前\((i-1)\)天也合法,所以考虑二分.
    • 判断可行性:差分:令\(d_i=a_i-a_{i-1}\),则区间\([l,r]+k\)等价于\(d_l+k,a_{r+1}-k\),先用差分处理操作,最后还原回\(a_i\)判断即可.
    #define N 1000005
    typedef long long ll;
    ll s[N],d[N];
    int a[N],l[N],r[N],n,m,lef,rig,mid;
    inline bool chk(int x){
    	memset(s,0,sizeof(s));
    	for(int i=1;i<=x;++i)
    		s[l[i]]+=d[i],s[r[i]+1]-=d[i];
    	ll now=0ll;
    	for(int i=1;i<=n;++i){
    		now+=s[i];
    		if(now>a[i]) return false;
    	}
    	return true;
    }
    inline void Aireen(){
    	n=read();m=read();
    	for(int i=1;i<=n;++i)
    		a[i]=read();
    	for(int i=1;i<=m;++i){
    		d[i]=1ll*read();l[i]=read();r[i]=read();
    	}
    	if(chk(n)){
    		 puts("0");return;
    	}
    	lef=1;rig=n;
    	while(lef<rig){
    		mid=lef+rig>>1;
    		if(!chk(mid)) rig=mid;
    		else lef=mid+1;
    	}
    	printf("-1\n%d\n",lef);
    }
    

    2017-10-27 13:45:00

  • 相关阅读:
    css中margin-left与left的区别
    Python文件和目录模块介绍:glob、shutil、ConfigParser
    [ Python入门教程 ] Python文件基本操作_os模块
    使用Pyinstaller转换.py文件为.exe可执行程序
    Windows命令行打开常用界面
    如何做好性能测试_流程篇
    Windows查看指定端口是否占用和查看进程
    ‘操作无法完成 ,因为其中的文件夹或文件已在另一程序中打开’问题解决
    bat脚本基础教程
    vi编辑器常用命令
  • 原文地址:https://www.cnblogs.com/AireenYe/p/15602445.html
Copyright © 2011-2022 走看看