CodeForces 46D Parking Lot (线段树区间合并)

题意:

长为len的停车场,一辆车要停下,则必须车尾留b长度的空间且车头与前面的车保持f长度。

有n次操作:1,长为val 的车要寻找车位停下,若能停下输出最小的停车点下标,否则输出-1

                    2,第val辆车开走了。

解:显然是线段树的区间合并。这里有个小技巧,就是树的范围是(-b,len+f-1).这里就保证了第一辆车停在0点,不用特判边界条件。为什么是len+f-1而不是len+f呢?因为,我的做法是这个点代表单位长度 ,0点也表示长度。

#include<iostream>
#include<string>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
#define LL long long
const int INF=0x3f7f7f7f;
const int MAXN=101005;
const double eps = 1e-10;
struct node
{
    int l,r,ll,rr,mx,c;
}tr[MAXN*4];
struct point
{
    int l,r;

}a[MAXN];
void pushup(int  id);
int max(int x,int y,int z)
{
    return max(x,max(y,z));
}
void build(int id,int l,int r)
{
    tr[id].l=l;
    tr[id].r=r;
    tr[id].c=0;
    if(l==r)
    {
        tr[id].ll=tr[id].rr=tr[id].mx=1;
    }
    else
    {
        int mid=(l+r)>>1;
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        pushup(id);
    }
}
void pushup(int id)
{
    tr[id].ll=tr[id*2].ll;
    tr[id].rr=tr[id*2+1].rr;
    if(tr[id].ll==tr[id*2].r-tr[id*2].l+1)tr[id].ll+=tr[id*2+1].ll;
    if(tr[id].rr==tr[id*2+1].r-tr[id*2+1].l+1)tr[id].rr+=tr[id*2].rr;
    tr[id].mx=max(tr[id*2].mx,tr[id*2+1].mx,tr[id*2].rr+tr[id*2+1].ll);
}
void pushdown(int id)
{
    tr[id*2].c=tr[id*2+1].c=1;
    tr[id].c=0;
    if(tr[id].mx)
    {
        tr[id*2].ll=tr[id*2].rr=tr[id*2].mx=tr[id*2].r-tr[id*2].l+1;
        tr[id*2+1].ll=tr[id*2+1].rr=tr[id*2+1].mx=tr[id*2+1].r-tr[id*2+1].l+1;
    }
    else
    {
        tr[id*2].ll=tr[id*2].rr=tr[id*2].mx=0;
        tr[id*2+1].ll=tr[id*2+1].rr=tr[id*2+1].mx=0;
    }

}
int quary(int id,int mx)
{
    if(tr[id].l==tr[id].r)
    {
        return tr[id].l;
    }
    else
    {
        //int mid=(tr[id].l+tr[id].r)/2;
        if(tr[id].c)pushdown(id);
        if(mx<=tr[id*2].mx)return quary(id*2,mx);
        else if(mx<=tr[id*2].rr+tr[id*2+1].ll)
        {
            return tr[id*2].r-tr[id*2].rr+1;
        }
        else
        {
            return quary(id*2+1,mx);
        }
    }
}
void update(int id,int l,int r,int val)
{
    if(l<=tr[id].l&&tr[id].r<=r)
    {
        tr[id].c=1;
        if(val==0)
        tr[id].ll=tr[id].rr=tr[id].mx=tr[id].r-tr[id].l+1;
        else
            tr[id].ll=tr[id].rr=tr[id].mx=0;
    }
    else
    {
        int mid=(tr[id].l+tr[id].r)>>1;
        if(tr[id].c)pushdown(id);
        if(r<=mid)update(id*2,l,r,val);
        else if(l>mid)update(id*2+1,l,r,val);
        else
        {
            update(id*2,l,r,val);
            update(id*2+1,l,r,val);

        }
        pushup(id);
    }
}
int main()
{
    int len,i,q,b,f;
    while(scanf("%d%d%d%d",&len,&b,&f,&q)!=EOF)
    {
        build(1,-b,len+f-1);
        int cnt=0;
        for(i=1;i<=q;i++)
        {
            int op,val;
            scanf("%d%d",&op,&val);
            if(op==1)
            {
                if(tr[1].mx<(val+b+f))
                {
                    puts("-1");
                    a[i].l=-1;
                    a[i].r=-1;
                    continue;
                }
                int ans=quary(1,val+b+f);
                printf("%d\n",ans+b);
                a[i].l=ans+b;
                a[i].r=ans+b+val-1;
                update(1,a[i].l,a[i].r,1);
            }
            else
            {
                a[i].l=-1;
                a[i].r=-1;
                update(1,a[val].l,a[val].r,0);
            }
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值