很容易想到一种动态的做法:平衡树……
或者是二分+树状数组
但,前者编程复杂度较大,而且据说会被卡(没试过);后者理论上超时(据说可以擦边过?);
所以要尝试新的算法;
倒着考虑,显然最后一个对象的位置是最容易确定,顺带着,容易发现,
在第i个人后插入,就是在当前队列中前面有i个空位的空位置;
于是还是可以用平衡数……
当然更简单快捷的方法是线段树,每个节点表示这个区间还有的空位数;
然后类比平衡树的查找k大,很快就能写成
1 var tree:array[0..600010] of longint; 2 p,a,w:array[0..600010] of longint; 3 n,i:longint; 4 5 procedure build(i,l,r:longint); 6 var m:longint; 7 begin 8 tree[i]:=r-l+1; 9 m:=(l+r) shr 1; 10 if l<>r then 11 begin 12 build(i*2,l,m); 13 build(i*2+1,m+1,r); 14 end; 15 end; 16 17 function ask(i,l,r,k:longint):longint; 18 var m:longint; 19 begin 20 if l=r then 21 begin 22 tree[i]:=0; 23 exit(l); 24 end; 25 m:=(l+r) shr 1; 26 if tree[i*2]>k then 27 begin 28 dec(tree[i*2]); //在查找的过程中顺便把区间空位数更新 29 exit(ask(i*2,l,m,k)); 30 end 31 else begin 32 dec(tree[i*2+1]); 33 exit(ask(i*2+1,m+1,r,k-tree[i*2])); //有没有觉得很平衡树找区间k值神似 34 end; 35 end; 36 37 begin 38 while not eoln do 39 begin 40 readln(n); 41 fillchar(tree,sizeof(tree),0); 42 build(1,1,n); 43 for i:=1 to n do 44 readln(p[i],a[i]); 45 for i:=n downto 1 do 46 w[i]:=ask(1,1,n,p[i]); //w代表每个点的位置 47 for i:=1 to n do 48 p[w[i]]:=a[i]; 49 for i:=1 to n do 50 begin 51 write(p[i]); 52 if i<>n then write(' '); //注意别PE了 53 end; 54 writeln; 55 end; 56 end.