题意:FJ有n头牛,编号为1~n,它们并没有按照编号的顺序排好队列。现在,FJ只知道每一个牛前面有多少只牛的编号比它大。问你能不能判断出所有牛的编号。
思路:线段树。关键:每次最后一只牛的编号是可以确定的,即为pre[i]+1,将其编号从所有牛中删除,则倒数第二只牛的编号又可以确定为pei[i]+1,依此类推。
代码如下:
#include<iostream>
using namespace std;
const int Max = 8005;
struct
{
int l, r, len; // 用len存储这个区间的数字个数。
}node[3*Max];
int pre[Max], ans[Max];
void BuildTree(int left, int right, int u)
{ // 建树。
node[u].l = left;
node[u].r = right;
node[u].len = right - left + 1;
if(left == right)
return;
BuildTree(left, (left+right)/2, 2*u);
BuildTree((left+right)/2+1, right, 2*u+1);
}
int query(int u, int num)
{ // 查询+维护,关键一点:所求值为当前区间的左起第num个元素。
node[u].len--; // 对访问到的区间维护len。
if(node[u].l == node[u].r)
return node[u].l;
// 情况1:左子区间的数字个数不够,则查询右子区间的左起第num - node[u<<1].len个元素。
if(node[2*u].len < num)
return query(2*u+1, num - node[2*u].len);
// 情况2:左子区间的数字个数足够,则依旧查询左子区间的左起第num个元素。
if(node[2*u].len >= num)
return query(2*u, num);
}
int main()
{
int n, i;
scanf("%d", &n);
pre[1] = 0;
for(i = 2; i <= n; i ++)
scanf("%d", &pre[i]);
BuildTree(1, n, 1);
for(i = n; i >= 1; i --) // 从后往前推断出每次最后一个数字。
ans[i] = query(1, pre[i]+1);
for(i = 1; i <= n; i ++)
printf("%d\n", ans[i]);
return 0;
}