这题需要逆向思维一下吧,两个地方注意下就行了。一个就是从后往前推,先把最后位置的确认了是第几个,再确认倒数第二个。
另一个就是想到怎样用线段树,一开始我想大概也跟前几篇博客那种按先后次序添加进来,但想了想,这题应该是按我们确认位置的次序,把已经确认的给踢出去,所以用线段树来维护L到R区间,依然未被确认位置的个数,在初始化的时候,由于肯定是全都未确认,所以可以用(r - l +1)来表示各区间的个数。
最后就是从后往前,一个个查询到底是哪个数(即叶子节点)就行。
说几句做这些题的感触:无论是树状数组还是线段树,我们只要理解了这两种数据结构,通常建树,修改,查询,都是比较简单的(至少现在看来),重点是我们怎样用这两种结构来维护数据,往往一个题目看上去跟这两种结构毫无关系,但仔细想想之后(发现更多是逆向思考),确实可以找出能用他们来维护数据的办法,我觉得这是相比于DP稍微好一点的地方(DP。。不多说,都是泪)
代码还是比较简单易懂的:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Scanner;
public class Main{
static Scanner sc = new Scanner(System.in);
static int n;
static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
static int [] sum;
static int [] ipt;
static int [] opt;
static void init(int l, int r, int rt) {
sum[rt] = r - l + 1;
if(l == r) return;
int m = (l+r) >> 1;
init(l, m, rt<<1);
init(m+1, r, rt<<1|1);
}
static int query(int rt, int l, int r, int val) {
sum[rt]--;
if(l == r)return l;
int m = (l+r)>>1;
if(sum[rt<<1] >= val)
return query(rt<<1, l, m, val);
else
return query(rt<<1|1, m+1, r, val - sum[rt<<1]);
}
public static void main(String[] args) throws IOException {
while(sc.hasNext()) {
n = sc.nextInt();
sum = new int[4*n+1];
ipt = new int[n+1];
opt = new int[n+1];
init(1,n,1);
for(int i = 2; i <= n; i++) {
ipt[i] = sc.nextInt();
}
for(int i = n; i >= 1; i--) {
opt[i] = query(1,1,n,ipt[i] +1);
}
for(int i = 1; i <= n; i++) {
System.out.println(opt[i]);
}
}
System.exit(0);
}
}