1266. [NOIP2012] 借教室 ★★☆ 輸入檔案: classrooms.in 輸出檔案: classrooms.out 簡單對比
時間限制:1 s 記憶體限制:128 MB 【題目描述】
在大學期間,經常需要租借教室。大到院系舉辦活動,小到學習小組自習討論,都需要 向學校申請借教室。教室的大小功能不同,借教室人的身份不同,借教室的手續也不一樣。
面對海量租借教室的資訊,我們自然希望編程解決這個問題。
我們需要處理接下來n天的借教室資訊,其中第i天學校有ri個教室可供租借。共有m份 訂單,每份訂單用三個正整數描述,分別為dj,sj,tj,表示某租借者需要從第sj天到第tj天租 借教室(包括第sj天和第tj天),每天需要租借dj個教室。
我們假定,租借者對教室的大小、地點沒有要求。即對於每份訂單,我們只需要每天提 供dj個教室,而它們具體是哪些教室,每天是否是相同的教室則不用考慮。
借教室的原則是先到先得,也就是說我們要按照訂單的先後順序依次為每份訂單分配教 室。如果在分配的過程中遇到一份訂單無法完全滿足,則需要停止教室的分配,通知當前申 請人修改訂單。這裡的無法滿足指從第sj天到第tj天中有至少一天剩餘的教室數量不足dj個。
現在我們需要知道,是否會有訂單無法完全滿足。如果有,需要通知哪一個申請人修改 訂單。 【輸入格式】
第一行包含兩個正整數n,m,表示天數和訂單的數量。
第二行包含n個正整數,其中第i個數為ri,表示第i天可用於租借的教室數量。
接下來有m行,每行包含三個正整數dj,sj,tj,表示租借的數量,租借開始、結束分別在 第幾天。
每行相鄰的兩個數之間均用一個空格隔開。天數與訂單均用從1開始的整數編號。 【輸出格式】
如果所有訂單均可滿足,則輸出只有一行,包含一個整數 0。否則(訂單無法完全滿足) 輸出兩行,第一行輸出一個負整數-1,第二行輸出需要修改訂單的申請人編號。 【範例輸入】
4 3 2 5 4 3 2 1 3 3 2 4 4 2 4
【範例輸出】
-12
【輸入輸出範例說明】
第 1 份訂單滿足後,4 天剩餘的教室數分別為 0,3,2,3。第 2 份訂單要求第 2 天到 第 4 天每天提供 3 個教室,而第 3 天剩餘的教室數為 2,因此無法滿足。分配停止,通知第 2 個申請人修改訂單。 【資料範圍】
對於 10%的資料,有1 ≤ n,m ≤ 10;
對於 30%的資料,有1 ≤ n,m ≤ 1000;
對於 70%的資料,有1 ≤ n,m ≤ 10^5;
對於 100%的資料,有1 ≤ n,m ≤ 10^6,0 ≤ ri,dj ≤ 10^9,1 ≤ sj ≤ tj ≤ n。
首先可以類比 當年考試可以45分。。。。我是蒟蒻就類比的。。
現在可以看出來這是個很裸的線段樹(裸但是不是正解)
維護最小值
查詢minv[1]
區間更新
當年可以得到85/90/95分
#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int lim=1000011;int minv[lim<<2],addv[lim<<2];int m,n,x,y,w;int a,b,c;void pushup(int o){minv[o]=min(minv[o<<1],minv[o<<1|1]);}void build(int o,int l,int r){ if(l==r) { scanf("%d",&minv[o]); return; } int m=(l+r)>>1; build(o<<1,l,m); build(o<<1|1,m+1,r); pushup(o);}void pushdown(int o){ addv[o<<1]+=addv[o]; addv[o<<1|1]+=addv[o]; minv[o<<1]+=addv[o]; minv[o<<1|1]+=addv[o]; addv[o]=0;}void add(int o,int l,int r){ if(l>=x&&r<=y) { addv[o]+=w; minv[o]+=w; return; } pushdown(o); int m=(l+r)>>1; if(x<=m)add(o<<1,l,m); if(y>m)add(o<<1|1,m+1,r); pushup(o);}int main(){ freopen("classrooms.in","r",stdin);freopen("classrooms.out","w",stdout); scanf("%d%d",&m,&n); build(1,1,m); for(a=1;a<=n;a++) { scanf("%d%d%d",&w,&x,&y); w=-w; add(1,1,m); if(minv[1]<0) { cout<<-1<<'\n'<<a<<'\n'; return 0; } } cout<<0<<endl; return 0;}
可是 正解是二分。。。二分啊二分。。。
#include<iostream>#include<cstdio>#include<cstring>using namespace std;int s[1000011];struct self{int x,y,w;}g[1000011];int m,n,a,b,c,d;int l,r,mid,now;int ans;void work(int l,int r){ int a; if(r>now) for(a=now+1;a<=r;a++) { s[g[a].x]-=g[a].w; s[g[a].y+1]+=g[a].w; } else for(a=r+1;a<=now;a++) { s[g[a].x]+=g[a].w; s[g[a].y+1]-=g[a].w; } now=r;}bool ok(){ int ret=0,a; for(a=1;a<=m;a++) { ret+=s[a]; if(ret<0)return false; } return true;}int main(){ freopen("classrooms.in","r",stdin); freopen("classrooms.out","w",stdout); scanf("%d%d",&m,&n); b=c=0; for(a=1;a<=m;a++) { scanf("%d",&c); s[a]=c-b; b=c; } for(a=1;a<=n;a++)scanf("%d%d%d",&g[a].w,&g[a].x,&g[a].y); l=1;r=m;ans=-1; while(l<=r) { mid=(l+r)>>1; work(1,mid); if(ok()) l=mid+1; else { r=mid-1; ans=mid; } } if(ans==-1)cout<<0<<endl; else cout<<-1<<endl<<ans<<endl;return 0;}