题目大意:
有N个数,为1~N,给出N-1个a[i]表示前i个数有多少个数比当前的数要小,因为a[1]=0所以输入从a[2]开始,即输入a[2],a[3]……a[n-1],a[n]。
2 <= N <= 8,000
题解:
跟这题有点类似:
http://blog.csdn.net/gx_man_vip/article/details/71640465
线段树:
首先我们可以发现从最后一个数开始插入,对于他的整个结果就不会产生改变。
然后我们倒着插入数进入线段树:
首先建树:
tree[i]表示它所代表的区间[l,r]有多少个没有被填入数,即空白~。
然后插入:
pos表示要插入到当前区间[l,r]的第pos个位置,注意这里所说的第pos个位置,是除去已经占用了的位置后的,每一次插入的时候,如果左子树已经插的没有位置了即tree[p*2] < pos,这时候就插入到右子树上,并且pos要减去左子树占用的格子数。
pos=a[i]+1,因为每一次插入因为前面有a[i]个小于自己的。
var
ans,tree:array [0..100001] of longint;
p:array [0..8001] of longint;
i,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[i]:=l
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
readln(n);
build(1,1,n);
for i:=2 to n do readln(p[i]);
for i:=n downto 1 do
insert(1,1,n,p[i]+1);
for i:=1 to n do writeln(ans[i]);
end.