Codeforces 46D Parking Lot

题意

直线停车场长度 L ( 10 ≤ L ≤ 1 0 5 ) L(10 \le L \le 10^5) L(10L105),车长 x x x,头尾还需空出 b , f ( 1 ≤ x ≤ 1000 , 1 ≤ b , f ≤ 100 ) b,f(1\le x \le1000, 1\le b,f \le 100) b,f(1x1000,1b,f100)的距离。最多有100次操作:停车和出车操作。对于每个停车操作输出这辆车停的位置(尽量靠左的位置),对于出车操作保证这里车是在停车场内的

算法:线段树区间更新

100次操作次数似乎可以暴力模拟解决,不过对于区间操作的问题,应该交给线段树,这是带区间更新的线段树模板题。需要注意的细节是查询时区间是 b + x + f b+x+f b+x+f,更新时 b , f b,f b,f可以重合,边界是可以忽略 b , f b,f b,f

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const int maxn = 110000;
int l, b, f;
int a[110], c[110];
int vis[maxn << 2], sum[maxn << 2], lsum[maxn << 2], rsum[maxn << 2];

void build(int l, int r, int node)
{
    vis[node] = -1;
    lsum[node] = rsum[node] = sum[node] = r - l + 1;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(l, mid, node << 1);
    build(mid + 1, r, node << 1 | 1);
}

void pushdown(int l, int r, int node)
{
    int len = r - l + 1;
    int lnode = node << 1;
    int rnode = lnode | 1;
    if (vis[node] != -1)
    {
        vis[lnode] = vis[rnode] = vis[node];
        lsum[lnode] = rsum[lnode] = sum[lnode] = vis[node] ? 0 : len - (len >> 1); 
        lsum[rnode] = rsum[rnode] = sum[rnode] = vis[node] ? 0 : len >> 1; 
        vis[node] = -1;
    }
}

int query(int a, int l, int r, int node)
{
    if (l == r)
        return l;
    pushdown(l, r, node);
    int mid = (l + r) >> 1;
    int lnode = node << 1;
    int rnode = lnode | 1;
    if (sum[lnode] >= a)
        return query(a, l, mid, lnode);
    else if (rsum[lnode] + lsum[rnode] >= a)
        return mid - rsum[lnode] + 1 + b;
    else
        return query(a, mid + 1, r, rnode);
}

void pushup(int l, int r, int node)
{
    int len = r - l + 1;
    int lnode = node << 1;
    int rnode = lnode | 1;
    lsum[node] = lsum[lnode];
    rsum[node] = rsum[rnode];
    if (lsum[node] == len - (len >> 1))
        lsum[node] += lsum[rnode];
    if (rsum[node] == (len >> 1))
        rsum[node] += rsum[lnode];
    sum[node] = max(rsum[lnode] + lsum[rnode], max(sum[lnode], sum[rnode]));
}

void update(int x, int y, int v, int l, int r, int node)
{
    if (x <= l && y >= r)
    {
        lsum[node] = rsum[node] = sum[node] = v ? 0 : r - l + 1;
        vis[node] = v;
        return ;
    }
    pushdown(l, r, node);
    int mid = (l + r) >> 1;
    if (x <= mid)
        update(x, y, v, l, mid, node << 1);
    if (y > mid)
        update(x, y, v, mid + 1, r, node << 1 | 1);
    pushup(l, r, node);
}

int main()
{
    int n, opt, x, cnt = 0;
    while (scanf("%d%d%d", &l, &b, &f) != EOF)
    {
        l += b + f;
        build(1, l, 1);
        scanf("%d", &n);
        while (n--)
        {
            scanf("%d", &opt);
            cnt++;
            if (opt == 1)
            {
                scanf("%d", a + cnt);
                if (sum[1] < a[cnt] + b + f)
                    printf("-1\n");
                else {
                    c[cnt] = query(a[cnt] + b + f, 1, l, 1);
                    update(c[cnt], c[cnt] + a[cnt] - 1, 1, 1, l, 1);
                    printf("%d\n", c[cnt] - 1 - b);
                }
            } else if (opt == 2)
            {
                scanf("%d", &x);
                update(c[x], c[x] + a[x] - 1, 0, 1, l, 1);
            }
        }
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值