1. 程式人生 > >【NOIP2012】借教室

【NOIP2012】借教室

停止 blog 最小 style clas noi scan 編號 當前

在大學期間,經常需要租借教室。大到院系舉辦活動,小到學習小組自習討論,都需要 向學校申請借教室。教室的大小功能不同,借教室人的身份不同,借教室的手續也不一樣。
面對海量租借教室的信息,我們自然希望編程解決這個問題。
我們需要處理接下來n天的借教室信息,其中第i天學校有ri個教室可供租借。共有m份 訂單,每份訂單用三個正整數描述,分別為dj,sj,tj,表示某租借者需要從第sj天到第tj天租 借教室(包括第sj天和第tj天),每天需要租借dj個教室。
我們假定,租借者對教室的大小、地點沒有要求。即對於每份訂單,我們只需要每天提 供dj個教室,而它們具體是哪些教室,每天是否是相同的教室則不用考慮。
借教室的原則是先到先得,也就是說我們要按照訂單的先後順序依次為每份訂單分配教 室。如果在分配的過程中遇到一份訂單無法完全滿足,則需要停止教室的分配,通知當前申 請人修改訂單。這裏的無法滿足指從第sj天到第tj天中有至少一天剩余的教室數量不足dj個。
現在我們需要知道,是否會有訂單無法完全滿足。如果有,需要通知哪一個申請人修改 訂單。

Input

第一行包含兩個正整數n,m,表示天數和訂單的數量。
第二行包含n個正整數,其中第i個數為ri,表示第i天可用於租借的教室數量。
接下來有m行,每行包含三個正整數dj,sj,tj,表示租借的數量,租借開始、結束分別在 第幾天。
每行相鄰的兩個數之間均用一個空格隔開。天數與訂單均用從1開始的整數編號。

Output

如果所有訂單均可滿足,則輸出只有一行,包含一個整數 0。否則(訂單無法完全滿足) 輸出兩行,第一行輸出一個負整數-1,第二行輸出需要修改訂單的申請人編號。

題解:   oj的標簽是平衡樹,其實只要一顆線段樹就可以了,你想我們需要一個nlogn的算法,顯然是用數據結構去優化暴力,我們要維護的是每天剩余的教室數,但仔細分析一下,不難發現,因為每個詢問都是對於一個區間,那麽只要區間的最小值夠詢問才能滿足,所以可以考慮用線段樹維護一下區間的最小值,當然減的時候一定要打懶標記,不然復雜度就不對了。 代碼:
#include<iostream>
#include
<stdio.h> #include<stdlib.h> const int MAXN=1000010; int day[MAXN],n,m; struct tree{ int l,r,m,lz; }a[MAXN*4]; int min(int x,int y){ if(x<y) return x; return y; } void build(int id,int l,int r){ if(l==r){ a[id].l=l,a[id].r=r; a[id].m=day[l],a[id].lz=0;
return; } a[id].l=l,a[id].r=r,a[id].lz=0; int mid=(l+r)/2; build(id*2,l,mid); build(id*2+1,mid+1,r); a[id].m=min(a[id*2].m,a[id*2+1].m); } void lazz(int id){ if(a[id].lz!=0){ a[id*2].lz+=a[id].lz,a[id*2+1].lz+=a[id].lz; a[id*2].m-=a[id].lz,a[id*2+1].m-=a[id].lz; a[id].lz=0; return; } } int kanxun(int l,int r,int id){ int L=a[id].l,R=a[id].r,mid=(L+R)/2; if(L==l&&R==r){ return a[id].m; } lazz(id); if(r<=mid) return kanxun(l,r,id*2); else if(l>mid) return kanxun(l,r,id*2+1); else return min(kanxun(l,mid,id*2),kanxun(mid+1,r,id*2+1)); //這裏之所以不要加update是因為我們認為,下放懶標記之後的已經把 //區間所存的數修改正確,而不受兒子結點的影響,因為兒子的laze就是從爸爸那拿來的 } void update(int l,int r,int id,int x){ int L=a[id].l,R=a[id].r,mid=(L+R)/2; if(L==l&&R==r){ a[id].lz+=x; a[id].m-=x; return; } lazz(id); if(r<=mid) update(l,r,id*2,x); else if(l>mid) update(l,r,id*2+1,x); else update(l,mid,id*2,x),update(mid+1,r,id*2+1,x); a[id].m=min(a[id*2].m,a[id*2+1].m); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&day[i]); build(1,1,n); for(int i=1;i<=m;i++){ int z,x,y; scanf("%d%d%d",&z,&x,&y); int have=kanxun(x,y,1); if(have<z){printf("-1\n%d",i);return 0;} update(x,y,1,z); } printf("0\n"); return 0; }

【NOIP2012】借教室