zoukankan      html  css  js  c++  java
  • 阿 Q 的停车场

    问题描述
    刚拿到驾照的 KJ 总喜欢开着车到处兜风,玩完了再把车停到阿 Q 的停车场里,虽然 她对自己停车的水平很有信心,但她还是不放心其他人的停车水平,尤其是 Kelukin。于是, 她每次都把自己的爱车停在距离其它车最远的一个车位。KJ 觉得自己这样的策略非常科 学,于是她开始想:在一个停车场中有一排车位,从左到右编号为 1 到 n,初始时全部是 空的。有若干汽车,进出停车场共 m 次。对于每辆进入停车场的汽车,会选择与其它车距 离最小值最大的一个车位,若有多个符合条件,选择最左边一个。KJ 想着想着就睡着了, 在她一旁的 Kelukin 想帮她完成这个心愿,但是他又非常的懒,不愿意自己动手,于是就把 这个问题就留给了你:在 KJ 理想的阿 Q 的停车场中,给你车辆进出的操作序列,依次输 出每辆车的车位编号。

    输入格式
    第一行,两个整数 n 和 m,表示停车场大小和操作数;
    接下来 m 行,每行两个整数 F 和 x F 是 1 表示编号为 x 的车进停车场; F 是 2 表示编号为 x 的车出停车场;
    保证操作合法,即: 出停车场的车一定目前仍在停车场里; 停车场内的车不会超过 n;

    输出格式
    对于所有操作 1,输出一个整数,表示该车车位的编号

    样例输入
    7 11
    1 15
    1 123123
    1 3
    1 5
    2 123123
    2 15
    1 21
    2 3
    1 6
    1 7
    1 8

    样例输出
    1
    7
    4
    2
    7
    4
    1
    3

    提示
    【数据范围】
    对 30%的数据 n<=1000 ,m<=1000 对
    60%的数据 n<=200000,m<=2000
    对 100%的数据 n,m<=200000,
    车的编号小于等于 10^6

    分析:
    考场上我这个zz想了一种堆的做法,
    然而实现起来有缺陷,
    后来听他们说这是一道蛮简单的线段树,
    感觉自己退役算了。。。

    根据题目的要求,
    0号和n+1位是不能视为有车的,
    所以这两个位置需要特判,
    一般情况下,只要找出该区间内没有停车的最远的区间,
    区间长度>>1就是下一辆要停的车与其他车相距的最远距离
    (不知道自己在说什么)

    要维护四个量
    分别是x,y,mid,p
    x表示在当前结点线段树所在区间,最左边的车停的位置
    同理,y表示做右边的车所停的位置
    mid表示在这个小区间[x,y]中的紧邻的两辆车的最长距离除以2后的值
    p表示取得mid值是所在的紧邻的两辆车的中间位置,也就是在[x,y]中的答案值

    网上的代码都超级**
    实在是看不懂,废了洪荒之力码完代码。。。

    最复杂的过程就是停车(其实也很好理解):
    每一次在新停车的时候,
    都查看一下第一个节点的信息(线段树的根节点记录的是整个区间的信息)
    每辆车都有三个可能停的位置
    tree[1].p,1,n
    这三个点的停车相聚最远距离分别是
    tree[1].mid,
    tree[1].x-1(假使第一个位置没有停车)
    n-tree[1].y(假使最后一个位置没有停车)

    从三个位置中选择一个最优的添加

    update的时候分别维护就好了
    tree[bh].x=tree[lc].x;
    tree[bh].y=tree[rc].y;
    tree[bh].mid和tree[bh].p需要从三个值中择优:
    tree[lc]
    tree[rc].mid
    tree[rc].y-tree[lc].x+1; //两个区间之间的空位

    这里写代码片
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    
    using namespace std;
    
    const int N=200002;
    struct node{
        int x,y,mid,p;
    };
    node tree[N<<4];
    int n,m;
    int car[1000001];  //车的位置,如果你6可以加离散化啊 
    
    void update(int bh)
    {
        int lc=bh<<1;
        int rc=(bh<<1)+1;
        if (bh)
        {
            tree[bh].x=tree[lc].x;
            tree[bh].y=tree[rc].y;
            tree[bh].mid=tree[lc].mid;
            tree[bh].p=tree[lc].p;
            if (tree[rc].mid>tree[bh].mid)
            {
                tree[bh].mid=tree[rc].mid;  tree[bh].p=tree[rc].p;
            }
            int l=tree[rc].y-tree[lc].x+1;  //两个区间之间的空位
            if (l>tree[bh].mid)
            {
                tree[bh].mid=l;
                tree[bh].p=(tree[lc].y+tree[rc].x)>>1;
            } 
        }
        return;
    }
    
    void add(int bh,int l,int r,int wz,int z)
    {
        if (l==wz&&l==r)
        {
            if (z==1)
            {
                tree[bh].x=l;
                tree[bh].y=r;
                tree[bh].mid=0;   //节点上有车了,当然就没有mid和p值了 
                tree[bh].p=0;
                return;
            }
            else
            {
                tree[bh].x=0;
                tree[bh].y=0;
                tree[bh].mid=0;
                tree[bh].p=0;
                return;
            }
    
        }
        int mid=(l+r)>>1;
        if (wz<=mid) add(bh<<1,l,mid,wz,z);
        if (wz>mid) add((bh<<1)+1,mid+1,r,wz,z);
        update(bh);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        {
            int opt,u;
            scanf("%d%d",&opt,&u);
            if (opt==1)
            {
                if (tree[1].x==0)  //整颗线段树的信息都集中在根节点 
                {
                    car[u]=1;  //整个停车场都是空的 
                }
                else
                {
                    int mx=-1;
                    if (tree[1].x-1>mx)
                    {
                        mx=tree[1].x-1;
                        car[u]=1;  //第一个车位没人停 
                    }
                    if (tree[1].mid>mx)   
                    {
                        mx=tree[1].mid;
                        car[u]=tree[1].p;
                    }
                    if (n-tree[1].y>mx)
                    {   //最后的车位没人停 
                        mx=n-tree[1].y;
                        car[u]=n;
                    }
                }
                printf("%d
    ",car[u]);
                add(1,1,n,1,1); 
            }
            else
            {
                add(1,1,n,car[u],-1);  //出停车场 
            }
        }
        return 0;
    }
  • 相关阅读:
    第七十一课 图的定义与操作
    第七十课 二叉树经典面试题分析
    第六十九课 二叉树的线索化实现
    第六十八课 二叉树的比较与相加
    第六十七课 二叉树的典型遍历方式
    第六十六课 二叉树结构的层次遍历
    第六十五课 二叉树中属性操作的实现
    2018华为笔试题
    交错01串
    操作序列(网易)
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673536.html
Copyright © 2011-2022 走看看