P1083 借教室(二分)
阿新 • • 發佈:2018-11-01
這個題的單調性在哪裡呢?
顯然(額),如果你在分配第個訂單時就gg了,那麼往後的訂單就都沒法分配了。
所以,我們二分一下到底是哪個訂單時gg了:
假設我們check 分配到第個訂單,設陣列表示分配完第個訂單後第天還有多少個教室供後來的第後的訂單分配,那麼,當陣列中出現的情況時,表示第天的教室已經被多個訂單分配且無法滿足所有的前個訂單。那二分流程就出來了:
1.選取.
2.檢查分配到第個訂單時是否gg,若gg了,則有可能在分配第個訂單前的訂單時就已經gg了,令.若沒有gg,則令。
最後注意:若出現的情況時,check函式直接返回合法即可。
最後說一說如何實現check函式的
由於我只需要知道分配完第後的陣列的值,但修改卻是次的。
多次修改,單次查詢:差分陣列!!!
上程式碼:
#include<cstdio> #include<cstring> #include<iostream> #define ri register int using namespace std; const int MAXN=1000020; int n,q,a[MAXN],d[MAXN],s[MAXN],t[MAXN],l,r,mid,cha[MAXN],sum[MAXN]; bool check(int lst) { memset(cha,0,sizeof(cha)); memset(sum,0,sizeof(sum)); if(lst==0||lst==n+1) return 1; for(ri i=1;i<=lst;i++) cha[s[i]]-=d[i],cha[t[i]+1]+=d[i];//O(1)修改 //sum[i]:分配完mid個訂單後第i天還剩多少個空餘教室 //cha[i]:sum[i]-sum[i-1] for(ri i=1;i<=n;i++) sum[i]=sum[i-1]+cha[i]; for(ri i=1;i<=n;i++) { sum[i]+=a[i]; if(sum[i]<0) return 0; } return 1; } inline int read() { int x=0; char ch=getchar(); while(ch<'0'||'9'<ch) ch=getchar(); while('0'<=ch&&ch<='9') { x=(x <<3)+(x <<1)+(ch-'0'); ch=getchar(); } return x; } int main() { n=read(),q=read(); for(ri i=1;i<=n;i++) a[i]=read(); for(ri i=1;i<=q;i++) d[i]=read(),s[i]=read(),t[i]=read(); l=0,r=q+1; while(l+1<r) { mid=(l+r)>>1; if(check(mid)) l=mid; else r=mid; } for(ri i=l;i<=r;i++) if(!check(i)) { cout<<"-1"<<'\n'<<i; return 0; } //注意第l和r個訂單都有可能gg,所以按分配順序從小往大判斷 cout<<"0"; return 0; }