codeforces 46D 线段树 区间合并

来源:互联网 发布:java 轮询查询数据库 编辑:程序博客网 时间:2024/06/07 19:38

和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|1const 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;}
原创粉丝点击