poj 2828 Buy Tickets 线段树

题目: 输入n个有序对<pi, vi> pi表示在第pi个位置后面插入一个值为vi的人,并且pi是不降的。输出最终得到的v的序列。

这题做了大半个晚上,而且还是看了好久题解才做出来的,看来自己还是太水了。

首先大概思路就是从后往前处理,根据每一个人后面的人来推出这个人所处的位置,而重点就在于如何推出每个人的位置。首先建一颗线段树,节点储存的是该区间还有多少个空格。而对于每一个人所插入的位置x则表示该时刻这个人前面应该还剩x个空格(自己想为什么),若左节点的空格数大于x则搜索左节点,否则搜索右节点。注意在搜索右节点是要先把x减去左节点的空格数。

下面附程序:

var
  n,i:longint;
  t:array[1..600000,1..3] of longint;
  a,x,y:array[1..200000] of longint;

procedure hehe(d,l,r:longint);
var
  m:longint;
begin
  t[d,1]:=l;
  t[d,2]:=r;
  t[d,3]:=r-l+1;
  if l=r then exit;
  m:=(l+r) div 2;
  hehe(d*2,l,m);
  hehe(d*2+1,m+1,r);
end;

function work(d,x:longint):longint;
begin
  dec(t[d,3]);
  if t[d,1]=t[d,2] then exit(t[d,1]);
  if t[d*2,3]>x
    then work:=work(d*2,x)
    else work:=work(d*2+1,x-t[d*2,3]);
end;

begin
  while not eof do
  begin
    readln(n);
    hehe(1,1,n);
    for i:=1 to n do
      readln(x[i],y[i]);
    a[work(1,x[n])]:=y[n];
    for i:=n-1 downto 1 do
      a[work(1,x[i])]:=y[i]; 
    for i:=1 to n do
      write(a[i],' ');
    writeln;
  end;
end.


你可能感兴趣的:(poj 2828 Buy Tickets 线段树)