[CF46D]Parking Lot

题目:Parking Lot 

传送门:http://codeforces.com/problemset/problem/46/D

分析:

做法一:

1)这题和Hotel那题一样,也可以看做是求区间空位的问题,不过相对于Hotel那题细节会更多一些。

2)头和尾是不用考虑前和后是否有车的,但可以在$-B$和$L+F$这两个位置假装停了一辆车,这样就不用考虑第一辆插入的车和插入在最后的车啦,减少思考量。

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxN=100500;
int a[110],b[110];
struct Segment{
    int setL,setR,setN;
    int l0[maxN<<2],r0[maxN<<2],m0[maxN<<2],tag[maxN<<2];
    void Down(int v,int l,int r){
        if(tag[v]==-1)return;
        int mid=(l+r)>>1;
        l0[v<<1]=r0[v<<1]=m0[v<<1]=(!tag[v])*(mid-l+1);
        l0[v<<1^1]=r0[v<<1^1]=m0[v<<1^1]=(!tag[v])*(r-mid);
        tag[v<<1]=tag[v<<1^1]=tag[v];tag[v]=-1;
    }
    void Up(int v,int l,int r){
        int mid=(l+r)>>1;
        if(l0[v<<1]==(mid-l+1))l0[v]=l0[v<<1]+l0[v<<1^1];else l0[v]=l0[v<<1];
        if(r0[v<<1^1]==(r-mid))r0[v]=r0[v<<1]+r0[v<<1^1];else r0[v]=r0[v<<1^1];
        m0[v]=max(max(m0[v<<1],m0[v<<1^1]),r0[v<<1]+l0[v<<1^1]);
    }
    int que(int v,int l,int r){
        if(l==r)return l;
        Down(v,l,r);
        int mid=(l+r)>>1;
        if(m0[v<<1]>=setN)return que(v<<1,l,mid);
        if(r0[v<<1]+l0[v<<1^1]>=setN) return mid-r0[v<<1]+1;
        return que(v<<1^1,mid+1,r);
    }
    void set(int v,int l,int r){
        if(setL<=l && r<=setR){
            l0[v]=r0[v]=m0[v]=(!setN)*(r-l+1);
            tag[v]=setN;return;
        }
        Down(v,l,r);
        int mid=(l+r)>>1;
        if(setL<=mid)set(v<<1,l,mid);
        if(mid< setR)set(v<<1^1,mid+1,r);
        Up(v,l,r);
    }
}T;
int main(){
    int L,B,F,n;
    scanf("%d%d%d%d",&L,&B,&F,&n);
    T.l0[1]=T.r0[1]=T.m0[1]=B+L+F;
    for(int op,x,d,td,i=1;i<=n;++i){
        scanf("%d",&op);
        if(op==1){
            scanf("%d",&td);d=B+td+F;
            if(T.m0[1]<d)puts("-1");
            else{
                T.setN=d;x=T.que(1,-B,L+F-1);
                a[i]=T.setL=x+B;b[i]=T.setR=a[i]+td-1;T.setN=1;
                T.set(1,-B,L+F-1);
                printf("%d
",a[i]);
            }
        }else{
            scanf("%d",&td);
            T.setL=a[td];T.setR=b[td];T.setN=0;
            T.set(1,-B,L+F-1);
        }
    }
    return 0;
}

做法二:

2)关注到$n$非常小

3)利用map来储存停了车区间,保留区间头尾就好了

4)插入车:遍历map,查看两个停车区间的中间是否可以停下当前这辆车

代码:

#include <bits/stdc++.h>
using namespace std;
map<int,int>mp;
int a[110];
int main(){
    int L,B,F,n;
    scanf("%d%d%d%d",&L,&B,&F,&n);
    mp[-B]=-B;mp[L+F]=L+F;
    for(int i=1,op,x;i<=n;++i){
        scanf("%d%d",&op,&x);
        if(op==1){
            a[i]=-1;
            for(auto it1=mp.begin(),it2=++mp.begin();it2!=mp.end();++it1,++it2) {
                if(it2->first - it1->second >=B+x+F) {
                    a[i]=it1->second + B;
                    mp[a[i]]=a[i]+x;
                    break;
                }
            }
            printf("%d
",a[i]);
        }else mp.erase(a[x]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hjj1871984569/p/10426409.html