poj 2828 Buy Tickets

Description

Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue…

The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he had to travel by train to Mianyang, Sichuan Province for the winter camp selection of the national team of Olympiad in Informatics.

It was one o’clock a.m. and dark outside. Chill wind from the northwest did not scare off the people in the queue. The cold night gave the Little Cat a shiver. Why not find a problem to think about? That was none the less better than freezing to death!

People kept jumping the queue. Since it was too dark around, such moves would not be discovered even by the people adjacent to the queue-jumpers. “If every person in the queue is assigned an integral value and all the information about those who have jumped the queue and where they stand after queue-jumping is given, can I find out the final order of people in the queue?” Thought the Little Cat.

Input

There will be several test cases in the input. Each test case consists of N + 1 lines where N (1 ≤ N ≤ 200,000) is given in the first line of the test case. The next N lines contain the pairs of values Posi and Vali in the increasing order of i (1 ≤ iN). For each i, the ranges and meanings of Posi and Vali are as follows:

  • Posi ∈ [0, i − 1] — The i-th person came to the queue and stood right behind the Posi-th person in the queue. The booking office was considered the 0th person and the person at the front of the queue was considered the first person in the queue.
  • Vali ∈ [0, 32767] — The i-th person was assigned the value Vali.

There no blank lines between test cases. Proceed to the end of input.

Output

For each test cases, output a single line of space-separated integers which are the values of people in the order they stand in the queue.

Sample Input

4
0 77
1 51
1 33
2 69
4
0 20523
1 19243
1 3890
0 31492

Sample Output

77 33 69 51
31492 20523 3890 19243

Hint

The figure below shows how the Little Cat found out the final order of people in the queue described in the first test case of the sample input.

poj <wbr>2828 <wbr>Buy <wbr>Tickets

Source

 
 
 
题意:多组数据。针对每一组数据。题目会给出n条操作(pos[i],val[i])。表示在pos[i]右边插入val[i]的值,并保证pos[i]<i(既保证数据合法)。最后输出操作后的数组。
 
//===============================================================================================
 
这道题很明显可以用平衡树,插入是最基本的操作,最后输出树的中序遍历即可。
 
可是通过观察可以发现,只有后面插入的数会影响之前插入的第i个数的位置,同时还必须满足插入的位置在第i个的前面。所以就可以从后往前做,每一次找到插入的位置,因为若是从后往前做,可能影响它位置的数都已经插入到数组中了,这时它的位置就唯一固定了。这样就可以得到操作后的数组了。
 
那么怎么找到当前数插入的确切位置呢?首先,在这个数插入之后,每一个在它位置之前插入的数都会且仅会将它向后推一格。所以,我们可以在确定了的之前的数的位置上加上一(即inc(c[x]))。这样,我们就可以找到一个最近的位置x,使得pos(i)+∑c[j]=x-1 (1<=j<=x),那么x即是当前数的位置。
为什么要强调最近的x呢?因为如果x不是最近的,那么有可能x的位置已经被放了数了。
即:
0 0 0 1 1 0 1 1
当pos[i]=4时,对于x=6,7,8都是符合上面的关系式的,但是明显7,8是不合法的。
 
怎么找到x呢?      二分+树状数组(线段树)
不推荐使用线段树,常数大,编程麻烦。
对于二分值mid,判断pos(i)+∑c[j]与x-1的大小关系,小等的时候r=mid,否则l=mid+1。具体看程序。
 
 
AC CODE
 
program pku_2828;
var a,v,p,c:array[1..200000] of longint;
      n:longint;
//============================================================================
function min(x,y:longint):longint;
begin
  if x<y then min:=x else min:=y;
end;
//============================================================================
function ask(x:longint):longint;                              //线段树询问1-x的和。
begin
  ask:=0;
  if x=0 then exit else
      while x>0 do
      begin
          inc(ask,c[x]);
          x:=x-x and (-x);
      end;
end;
//============================================================================
procedure ins(x:longint);                                            //线段树的插入操作。
begin
  while x<=n do
  begin
      inc(c[x]);
      x:=x+x and (-x);
  end;
end;
//============================================================================
procedure work;
var i,pre,now,l,r,mid:longint;
begin
  readln(n);
  for i:=1 to n do c[i]:=0;
  for i:=1 to n do readln(a[i],v[i]);
  for i:=n downto 1 do
  begin
      l:=a[i]+1; r:=min(l+n-i,n);  //二分。可以考虑最远可以插入的位置做小优化。
      repeat
          mid:=(l+r) shr 1;
          now:=ask(mid);
          if now<mid-a[i] then r:=mid else l:=mid+1;  //这里二分端点的问题最好自己搞清楚下确定答案所在的区间即可判断下一个区间。
      until l>=r;
      ins(l); p[l]:=v[i];
  end;
  for i:=1 to n do write(p[i],' '); writeln;
end;
//============================================================================
begin
  while not(eof) do work;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值