P1083 借教室(線段樹)
阿新 • • 發佈:2018-11-01
其實我第一次做借教室是用線段樹做的2333。
顯然(額),如果你在分配第個訂單時就gg了,那麼往後的訂單就都沒法分配了。
那麼gg的條件是什麼?
設陣列表示分配完第個訂單後第天還有多少個教室供後來的第個後的訂單分配,那麼,當陣列中出現的情況時,表示第天的教室已經被多個訂單分配且無法滿足所有的前個訂單。這時就gg了。
所以,我們開一棵線段樹維護陣列的最小值,將訂單看作為第個修改操作,將的所有值減去。當修改完後小於0,那麼當前的訂單就gg了,直接輸出-1和即可。若在進行完所有操作後始終,則說明所有訂單之間互不衝突,輸出0即可。
程式碼:
#include<cstdio> #include<iostream> #define ri register int using namespace std; const int MAXN=1000020; int n,q,a[MAXN],d[MAXN],s[MAXN],t[MAXN]; int l[MAXN<<2],r[MAXN<<2],minn[MAXN<<2],tag[MAXN<<2]; 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; } void pushup(int p) { minn[p]=min(minn[p <<1],minn[p <<1|1]); } void pushdown(int p) { minn[p <<1]-=tag[p],tag[p <<1]+=tag[p]; minn[p <<1|1]-=tag[p],tag[p <<1|1]+=tag[p]; tag[p]=0; } void build(int p,int lft,int rit) { l[p]=lft,r[p]=rit; if(l[p]==r[p]) { minn[p]=a[lft]; return; } int mid=(lft+rit)>>1; build(p <<1,lft,mid); build(p <<1|1,mid+1,rit); pushup(p); } void update(int p,int lft,int rit,int k) { if(lft<=l[p]&&r[p]<=rit) { minn[p]-=k;tag[p]+=k; return; } pushdown(p); if(lft<=r[p <<1]) update(p <<1,lft,rit,k); if(l[p <<1|1]<=rit) update(p <<1|1,lft,rit,k); pushup(p); } int main() { n=read(),q=read(); for(ri i=1;i<=n;i++) a[i]=read(); build(1,1,n); for(ri i=1;i<=q;i++) d[i]=read(),s[i]=read(),t[i]=read(); for(ri i=1;i<=q;i++) { update(1,s[i],t[i],d[i]); if(minn[1]<0) { cout<<"-1"<<'\n'<<i; return 0; } } cout<<"0"; return 0; }