[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; }
我爱学习,学习使我快乐