POJ P2828 Buy Tickets

题目大意:
有N个数值,他们要依次插入,每次输入a[i],b[i]表示b[i]插入到第a[i]个位置,即b[i]占用了第a[i]+1个位置,这个位置以后的人(包括这个位置的人)全都后退一格,求最后的整个队列的位置。
1 ≤ N ≤ 200,000
PS:每一组数据中有多组输入。

题解:
线段树:
根据题目可以发现,如果逆着插入每一个插队的人的话,是不会影响他前后的人(包括在他之前插队的人)的,也就是说最后的结果是不会改变的,所以我们逆序插入,然后
1.建树,tree[i]表示当前第i个结点所代表的区间[l,r]内还剩余多少个格子没有被覆盖。
2.pos表示要插入到当前区间[l,r]的第pos个位置(已经被占用的位置pos不累加),每一次插入的时候,如果左子树已经插的没有位置了即tree[p*2] < pos,这时候就插入到右子树上,并且pos要减去左子树占用的格子数。

初值:
tree[i]【代表区间[l,r]】=r-l+1

var
    ans,tree:array [0..1000001] of longint;
    p,q:array [0..200001] of longint;
    i,j,n:longint;

procedure build(p,l,r:longint);
var
    mid:longint;
begin
    mid:=(l+r) div 2;
    if l=r then tree[p]:=1
           else begin
                      build(p * 2,l,mid);
                      build(p*2+1,mid+1,r);
                      tree[p]:=tree[p*2]+tree[p*2+1];
                end;

end;

procedure insert(p,l,r,pos:longint);
var
     mid:longint;
begin
     dec(tree[p]);
     mid:=(l+r) div 2;
     if l=r then ans[r]:=q[i]
            else begin
                       if tree[p*2]>=pos
                          then insert(p * 2,l,mid,pos)
                          else insert(p*2+1,mid+1,r,pos-tree[p*2]);
                 end;
end;

begin
    while not eof do
    begin
          readln(n);
          build(1,1,n);
          for i:=1 to n do readln(p[i],q[i]);
          for i:=n downto 1 do
              insert(1,1,n,p[i]+1);
          for i:=1 to n do write(ans[i],' ');
          writeln;
    end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值