[GRYZ2015]阿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

样例输出








3

数据范围

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

思路

30%  

  第一边做打了一个爆搜,维护停车场和距离最大值两个数组,进出车辆各自维护,进车的时候两个指针分别指向左右端点,维护值即为原值和更新值中较小的;出车的时候因为不知道此时的值是谁赋给它的,所有把空车位全部填满重来一遍。

const ma=200000;

var f:array[1..ma] of longint;
    a:array[1..ma] of longint;
    n,m,k,x,y,num,ss,kk:longint;

function min(x,y:longint):longint;
begin
    if x<y then exit(x) else exit(y);
end;

procedure intt;
begin
    assign(input,'park.in');
    assign(output,'park.out');
    reset(input);
    rewrite(output);
end;

procedure outt;
begin
    close(input);
    close(output);
end;

function update1(x:longint):longint;
var i,j,k,sum,num:longint;
begin
    i:=x;j:=x;
    while i>=1 do
        begin
            if a[i]=0 then
                f[i]:=min(f[i],abs(x-i));
            dec(i);
        end;
    while j<=n do
        begin
            if a[j]=0 then
                f[j]:=min(f[j],abs(x-j));
            inc(j);
        end;
    num:=0;sum:=0;
    for i:=1 to n do
        if (a[i]=0)and(f[i]>sum) then
            begin
                sum:=f[i];
                num:=i;
            end;
    exit(num);
end;
//car in

function update2(x:longint):longint;
var i,j,num,sum:longint;
begin
    for i:=1 to n do
        if a[i]=0 then f[i]:=2139062143;
    for i:=1 to n do
        if a[i]<>0 then
            for j:=1 to n do
                if a[j]=0 then
                    f[j]:=min(f[j],abs(i-j));
    num:=0;sum:=0;
    for i:=1 to n do
        if (a[i]=0)and(f[i]>sum) then
            begin
                sum:=f[i];
                num:=i;
            end;
    exit(num);
end;
//car out

begin
    intt;
    fillchar(f,sizeof(f),127);
    fillchar(a,sizeof(a),0);
    readln(n,m);
    for k:=1 to m do
        begin
            readln(x,y);
            if k=1 then
                begin
                    a[1]:=y;
                    writeln(1);
                    ss:=update1(1);
                    continue;
                end;
            if x=1 then
                begin
                    writeln(ss);
                    a[ss]:=y;
                    f[ss]:=2139062143;
                    ss:=update1(ss);
                    continue;
                end;
            if x=2 then
                begin
                    for kk:=1 to n do
                        if a[kk]=y then
                            begin
                                a[kk]:=0;
                                f[kk]:=2139062143;
                                ss:=update2(kk);
                                break;
                            end;
                    continue;
                end;
        end;
    outt;
end.
View Code

45% 

  XYD维护了某车两侧的空车位,我也不知道是怎么维护的,反正也是爆搜。

program dddlk;
var a,l,r:array[0..200001]of longint;
    f:array[1..200000]of boolean;
    b:array[1..1000000]of longint;
    n,m,i,j,a1,a2,ans,b1,max,b2:longint;
begin
  assign(input,'park.in');
  assign(output,'park.out');
  reset(input);
  rewrite(output);
  ans:=1;
  read(n,m);
  a[0]:=-300000;
  a[n+1]:=-300000;
  l[0]:=-300000;
  r[n+1]:=500000;
  for i:=1 to n do
    a[i]:=maxlongint;
  for i:=1 to m do
    begin
      read(a1,a2);
      if a1=1
        then
          begin
            writeln(ans);
            b[a2]:=ans;
            f[ans]:=true;
            a[ans]:=0;
            r[ans]:=ans;
            l[ans]:=ans;
            b1:=ans-1;
            while(b1>0)and(not f[b1])do
              begin
                if a[b1]>ans-b1
                  then a[b1]:=ans-b1;
                r[b1]:=ans;
                dec(b1);
              end;
            b1:=ans+1;
            while(b1<n+1)and(not f[b1])do
              begin
                if a[b1]>b1-ans
                  then a[b1]:=b1-ans;
                l[b1]:=ans;
                inc(b1);
              end;
            max:=a[1];
            ans:=1;
            for j:=2 to n do
              if a[j]>max
                then
                  begin
                    max:=a[j];
                    ans:=j;
                  end;
          end
        else
          begin
            b2:=b[a2];
            b1:=b2-1;
            f[b2]:=false;
            while(b1>0)and(not f[b1])do
              begin
                r[b1]:=r[b2+1];
                if b1-l[b1]>r[b1]-b1
                  then a[b1]:=r[b1]-b1
                  else a[b1]:=b1-l[b1];
                dec(b1);
              end;
            b1:=b2+1;
            while(b1<n+1)and(not f[b1])do
              begin
                l[b1]:=l[b2-1];
                if b1-l[b1]>r[b1]-b1
                  then a[b1]:=r[b1]-b1
                  else a[b1]:=b1-l[b1];
                inc(b1);
              end;
            l[b2]:=l[b2-1];
            r[b2]:=r[b2+1];
            if b2-l[b2]>r[b2]-b2
              then a[b2]:=r[b2]-b2
              else a[b2]:=b2-l[b2];
            max:=a[1];
            for j:=2 to n do
              if a[j]>max
                then
                  begin
                    max:=a[j];
                    ans:=j;
                  end;
          end;
    end;
  close(input);
  close(output);
end.
View Code

60%

  不晓得这个怎么搞

100% 

  用线段树实现。(据某位大神说,可以用堆来做。然而我并不会)用线段树还是相对简单的。首先我们对区间[1..n]开一课线段树。对于每一个节点,维护4个值。分别是l,r,mid,p。l表示在当前结点线段树所在区间,最左边的车停的位置。同理,r表示做右边的车所停的位置。mid表示在这个小区间[l,r]中的紧邻的两辆车的最长距离除以2后的值。p表示取得mid值是所在的紧邻的两辆车的中间位置,也就是在[l,r]中的答案值。

  对于 1 询问:访问线段树的第一个节点,我们比较l-1,n-r,mid的值哪个更大,就选哪个,它们的答案依次是1,n,mid。假设我们求得的位置是car[x]。然后访问[car[x],car[x]]所在的线段树的叶子节点,初始化它的值,然后回溯,进行合并。对于h[x].l与h[x].r可以通过两个儿子的l,r信息得出。对于h[x].mid值,首先在左右儿子的mid值中去一个最大的值。其次考虑一种情况,就是夹在两个线段之间的距离,可以通过(h[x+x+1].l-h[x+x].r) div 2 的值得出在于mid进行比较,然后p就随着mid的值的更新而更新。 
对于2询问:访问询问车所在的位置,直接将它的叶子节点[car[x],car[x]]删除,然后回溯时,再做一次合并操作。即可

AC做法:http://blog.csdn.net/liuyuanzhe0515/article/details/47414221

const   maxc=1000005;maxn=200005;
type    node=record
        l,r,mid,p:longint;
    end;
var i,j,k,m,n,ch,num,sum:longint;
    car:array[1..maxc] of longint;
    h:array[1..4*maxn] of node;
procedure merger(x:longint);
var t:longint;
begin
    if h[x+x].l>0 then h[x].l:=h[x+x].l else h[x].l:=h[x+x+1].l;
    if h[x+x+1].r>0 then h[x].r:=h[x+x+1].r else h[x].r:=h[x+x].r;
    h[x].mid:=h[x+x].mid;
    h[x].p:=h[x+x].p;
    if (h[x+x+1].l>0) and (h[x+x].r>0) then begin
        t:=(h[x+x+1].l-h[x+x].r) div 2;
        if t>h[x].mid then begin
            h[x].mid:=t;
            h[x].p:=(h[x+x+1].l+h[x+x].r) div 2;
        end;
        if h[x+x+1].mid>h[x].mid then begin
            h[x].mid:=h[x+x+1].mid;
            h[x].p:=h[x+x+1].p;
        end;
    end;
end;
procedure work(x,l,r,num,kind:longint);
var mid:longint;
begin
    if l=r then begin
        if kind=2 then begin
            h[x].l:=0;h[x].r:=0;
            h[x].mid:=0;h[x].p:=0;
        end else begin
            h[x].l:=l;h[x].r:=r;
            h[x].mid:=0;h[x].p:=0;
        end;
        exit;
    end;
    mid:=(l+r)>>1;
    if num<=mid then work(x+x,l,mid,num,kind) else work(x+x+1,mid+1,r,num,kind);
    merger(x);
end;
begin
    readln(n,m);
    for i:=1 to m do begin
        readln(ch,num);
        if ch=1 then begin
            if h[1].l=0 then begin
                car[num]:=1;
            end else begin
                sum:=-maxlongint;
                if h[1].l-1>sum then begin
                    sum:=h[1].l-1;
                    car[num]:=1;
                end;
                if h[1].mid>sum then begin
                    sum:=h[1].mid;
                    car[num]:=h[1].p;
                end;
                if n-h[1].r>sum then begin
                    sum:=n-h[1].r;
                    car[num]:=n;
                end;
            end;
            writeln(car[num]);
            work(1,1,n,car[num],1);
        end else begin
            work(1,1,n,car[num],2);
        end;
    end;
end.
View Code

 

转载于:https://www.cnblogs.com/yangqingli/p/4927698.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值