【题】【区间线段树/set】NKOJ3480 【2015多校联训2】阿 Q 的停车场

22 篇文章 0 订阅
16 篇文章 0 订阅

NKOJ3480 【2015多校联训2】阿 Q 的停车场
时间限制 : 20000 MS 空间限制 : 265536 KB

问题描述
刚拿到驾照的 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

来源 by BS

思路:
法一:
线段树,
1、维护
维护单点1或0,表示停车与否。
维护从左向右能得到的最有效区间,右向左能得到的最有效区间,整个能得到的最有效区间。
2、有效区间定义:
第一关键字:停车后与最近的车的距离,越大越好。
第二关键字:左端点位置,越小越好。
第三关键字:区间总长度,越长越好。
3、操作
操作一,判断1开始的区间、n结尾的区间、max区间中谁有效距离最大以得到b得位置(首、尾区间特殊一些)。再点操作置1。
操作二,点操作置0.

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define END fclose(stdin),fclose(stdout);return 0
const int need=200004;
const int needk=1e6+7;

//....................................................
inline void in_(int & d)
{
    char t=getchar();
    while(t<'0'||t>'9') t=getchar();
    for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';
}
char o[100];
inline void out_(int x)
{   
    int l=1; 
    if(!x) putchar('0');  
    for(;x;x/=10) o[l++]=x%10+'0';  
    for(l--;l;l--)putchar(o[l]);  
    putchar('\n');  
}  
//....................................................
struct yf
{
    int a,b;
    inline int loc(){return (a+b)>>1;}
    inline int len(){return b-a+1;}
    inline int len2(){return loc()-a+1;}
    inline friend bool operator>(yf a,yf b)
    {
        if(a.len2()==b.len2()) 
        {
            if(a.a==b.a) return a.len()>b.len(); 
            return a.a<b.a;
        }
        return a.len2()>b.len2();
    }
    inline yf operator+(const yf& b)
    {
        yf ans;
        ans.a=a,ans.b=b.b;
        return ans;
    }
};

struct fy
{
    int a,b,val;
    yf fl,fr,max;
    inline int len(){return b-a+1;}
} w[need<<3];
#define ls (s<<1)
#define rs ((s<<1)|1)

inline void NBHB(int s)
{
    if(w[s].len()==1)
    {
        if(w[s].val==0) 
        {
            w[s].fl.b=w[s].a;
            w[s].max=w[s].fr=w[s].fl;
        }
        else 
        {
            w[s].fl.b=w[s].a-1;
            w[s].fr.a=w[s].b+1;
            w[s].max=w[s].fl;
        }
        return ;
    }
    if(w[rs].max>w[ls].max) w[s].max=w[rs].max;
    else w[s].max=w[ls].max;
    if(w[ls].fr+w[rs].fl>w[s].max) w[s].max=w[ls].fr+w[rs].fl;

    if(w[ls].len()==w[ls].fl.len())
    {
        w[s].fl.b=w[ls].a+w[ls].fl.len()+w[rs].fl.len()-1;
    }
    else w[s].fl.b=w[ls].fl.b;

    if(w[rs].len()==w[rs].fr.len())
    {
        w[s].fr.a=w[rs].b-w[rs].fr.len()-w[ls].fr.len()+1;
    }
    else w[s].fr.a=w[rs].fr.a;
}

void build(int s,int l,int r)
{
    w[s].a=w[s].fl.a=l,w[s].b=w[s].fr.b=r;
    if(l==r) 
    {
        w[s].val=0;
        NBHB(s);
        return ;
    }
    build(ls,l,(l+r)>>1),build(rs,(l+r)/2+1,r);
    NBHB(s);
}

int d,val;
int loc[needk];

inline void change(int s)
{
    if(w[s].len()==1)
    {
        w[s].val=val;
        NBHB(s);
        return ;
    }
    int mid=(w[s].b+w[s].a)>>1;
    if(d<=mid) change(ls);
    else change(rs);
    NBHB(s);
}
//....................................................

int main()
{
    int n,m;scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=1,a,b,lenl,lenr,lenm,temploc,templen;i<=m;i++)
    {
        in_(a),in_(b);
        if(a==1)
        {
            temploc=w[1].max.loc();
            lenm=templen=w[1].max.len2();
            lenl=w[1].fl.len();
            lenr=w[1].fr.len();
            if(lenl>=lenm) temploc=1,templen=lenl;
            if(lenr>templen) temploc=n; 
            loc[b]=temploc;
            out_(loc[b]);//printf("%d\n",loc[b]);
            d=loc[b],val=1;
            change(1);
        }
        else 
        {
            d=loc[b],val=0;
            change(1);
            loc[b]=0;
        }
    }
}

法二:
set
对于操作一,每次只需要选出一个最有效区间,考虑使用set或优先队列。
而操作一删除一点后变为两个区间,即删除一个,添加两个。对于操作二,每次需要合并两个区间,即删除两个,添加一个。
为删除指定区间,使用set,而不是优先队列。

再另开一个set,按顺序记录已停车的位置,方便合并时找到需合并的两个区间。

#include<cstdio>
#include<iostream>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int need=1e6+7;

int n,m;
int loc_[need];
//.........................................................
struct fy
{
    int a,b;
    inline int loc(){return (a+b)>>1;}
    inline int len() const
    {
        if(a==1) return b;
        if(b==n) return b-a+1;
        return (a+b)/2-a+1;
    }
};
struct yf{
inline bool operator() (const fy &a,const fy &b)
{
    if(a.len()==b.len())return a.a<b.a;
    return a.len()>b.len();
} };

typedef set<fy,yf> sf;
sf s;
sf::iterator sit;
typedef set<int> si;
si loc;
si::iterator lit,llnt,rlnt;
//.........................................................
inline void in_(int & d) 
{
    char t=getchar();
    while(t<'0'||t>'9') t=getchar();
    for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';
}
//.........................................................

int main()
{
    scanf("%d%d",&n,&m);
    s.insert((fy){1,n});
    loc.insert(0),loc.insert(n+1);
    fy temp,temp1;
    for(int i=1,a,b,k,ans;i<=m;i++)
    {
        in_(a),in_(b);
        if(a==1)
        {
            temp=*s.begin();
            s.erase(s.begin());
            if(temp.a==1) 
            {
                ans=1;
                temp.a=2;
                s.insert(temp);
            }
            else if(temp.b==n)
            {
                ans=n;
                temp.b=n-1;
                s.insert(temp);
            }
            else
            {
                ans=temp.loc();
                temp1=temp;
                temp.b=ans-1;
                temp1.a=ans+1;
                s.insert(temp),s.insert(temp1);
            }
            printf("%d\n",loc_[b]=ans);
            loc.insert(ans);
        }
        else
        {
            lit=loc.find(loc_[b]);
            temp.a=*(--lit)+1,temp.b=loc_[b]-1;
            s.erase(temp);
            temp1.a=loc_[b]+1,temp1.b=*(++++lit)-1;
            s.erase(temp1);
            temp.b=temp1.b;
            s.insert(temp);
            loc.erase(loc_[b]);//最后erasse 
            loc_[b]=0;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值