poj 2182

题意:FJn头牛,编号为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;
}

 

 

 

 

你可能感兴趣的:(poj)