codeforces 46D 线段树 区间合并
和poj 的hotel差不多,多了一些细节处理的过程
给一辆汽车安排空位的时候还需要和前后的车都保持一定的车距,如果前面没车或者后面没车,则可以停在边界上
典型的线段树区间合并
View Code
#include<cstdio> #include<cstring> #include<vector> #include<map> #include<algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn = 200010; int sum[maxn<<2],col[maxn<<2]; int lsum[maxn<<2],rsum[maxn<<2]; map<int,pair<int,int> >re; inline int max(int a,int b){ return a>b?a:b; } void pushup(int rt,int m){ lsum[rt]=lsum[rt<<1]; rsum[rt]=rsum[rt<<1|1]; if(lsum[rt]==(m-(m>>1))) lsum[rt]+=lsum[rt<<1|1]; if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1]; sum[rt]=max(sum[rt<<1],sum[rt<<1|1]); sum[rt]=max(rsum[rt<<1]+lsum[rt<<1|1],sum[rt]); } void pushdown(int rt,int m){ if(col[rt]!=-1){ lsum[rt<<1]=rsum[rt<<1]=sum[rt<<1]=col[rt] ? m-(m>>1) : 0 ; lsum[rt<<1|1]=rsum[rt<<1|1]=sum[rt<<1|1]=col[rt] ? (m>>1): 0; col[rt]=-1; } } void build(int l,int r,int rt){ lsum[rt]=rsum[rt]=sum[rt]=r-l+1; col[rt]=-1; if(l==r) return ; int m=(l+r)>>1; build(lson); build(rson); } void update(int L,int R,int c,int l,int r,int rt){ if(L<=l&&r<=R){ lsum[rt]=rsum[rt]=sum[rt]= c ? r-l+1:0; col[rt]=c; return ; } pushdown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); pushup(rt,r-l+1); } int query(int w,int l,int r,int rt){ if(l==r) return l; pushdown(rt,r-l+1); int m=(l+r)>>1; if(sum[rt<<1]>=w) return query(w,lson); else if(rsum[rt<<1]+lsum[rt<<1|1]>=w) return m-rsum[rt<<1]+1; else return query(w,rson); } int main() { int n,m,behind,front,op,a,b,pos,ops; while(scanf("%d%d%d",&n,&behind,&front)!=EOF) { ops=0; build(0,n-1+front,1); scanf("%d",&m); while(m--) { scanf("%d%d",&op,&a); ops++; if(op==1) { if(sum[1]>=a+behind+front || lsum[1] >= a+front) { if(lsum[1]>=a+front) pos=0; else pos=query(a+behind+front,0,n-1+front,1); if(pos!=0) { printf("%d\n",pos+behind); update(pos+behind,pos+behind+a-1,0,0,n-1+front,1); re[ops]=make_pair(pos+behind,pos+behind+a-1); } else { printf("0\n"); update(0,a-1,0,0,n-1+front,1); re[ops]=make_pair(0,a-1); } } else printf("-1\n"); } else { int l=(int)re[a].first,r=(int)re[a].second; update(l,r,1,0,n-1+front,1); } } } return 0; }
哥用线段树调了n久,神牛们却用如此简短的代码让我 汗颜
分析:因为需要插入的次数很小,所以可以直接记录,每辆汽车一次插入的位置,被占据的位置和空位间肯定是一段一段相邻的
即,比如有空位 a-b、c-d, b-c 被占据了,如果a-b不够长,那么指针就要往右移动两个位置了,即跳过中间被占据的位置
View Code
#include <cstdio> #include <cstring> #include <vector> #include <set> #include <algorithm> using namespace std; int L, B, F; int pos[105][2], tm=0; set<int> s; int main(void) { scanf("%d%d%d", &L, &B, &F); s.insert(-B); s.insert(L+F); int n; scanf("%d", &n); while(n--) { int x, y; scanf("%d%d", &x, &y); ++tm; if (x == 1) { int f=0; for(set<int>::iterator it=s.begin(); it!=s.end(); ) { set<int>::iterator nxt=it; ++nxt; if (nxt!=s.end() && ((*it)+B+y+F <= *nxt)) { printf("%d\n", (*it)+B); s.insert((*it)+B); s.insert((*it)+B+y); pos[tm][0] = *it+B; pos[tm][1] = *it+B+y; f=1; break; } ++it; if(it!=s.end()) ++it; } if(!f) puts("-1"); } else { s.erase(pos[y][0]); s.erase(pos[y][1]); } } return 0; }