IT民工
加油!

题意: 有n个数,从1到n,打乱顺序,现输入n-1个数,第i个数表示序列中第1到i-1的数比第i个数小的个数.

要求输出该序列。从后往前每次求“第k小”,如样例,第五个数前面有0个比它小的,它一定是1,将1在

线段树中删除,再看第四个数,前面有1个比它小的,它就是2、3、4、5中第2小的,以此类推。线段树求

第k小一般思路:数组中存放区间元素个数,自顶向下,左边个数小于k就走右边,并用k去掉左边个数,

否则走向左边,直到叶子结点就是第k小。 

/*Accepted    264K    47MS    C++    1061B    2012-07-24 12:19:42*/
#include<cstdio>
#include<cstring>

const int MAXN = 10005;
int T[MAXN << 2], cow[MAXN];
int M;

void build( int n)
{
    int i;
    for( M = 1; M < n + 2; M <<= 1)
    memset( T, 0, sizeof(int) * (M << 2));
    for( i = 1; i <= n; i ++)
        T[i + M] = 1; //存的是值为i的个数
    for( i = M - 1; i > 0 ; i --)
        T[i] = T[i << 1] + T[i << 1 | 1];
}

void update( int i)
{
    for( ; i ^= 1; i >>= 1)
        T[i >> 1] = T[i] + T[i ^ 1];
}

int query( int k)
{
    int i, j;
    for( i = 1; i < M;)
    {
        if( T[i << 1] < k)
            k -= T[i << 1], i = i << 1 | 1;
        else
            i <<= 1;
    }
    -- T[i]; //删除值为i-M的点
    update(i);
    return i - M;
}

int main()
{
    int n, i;
    while( scanf( "%d", &n) == 1)
    {
        build(n);
        cow[0] = 0;
        for( i = 1; i < n; i ++)
            scanf( "%d", &cow[i]);
        for( i = n - 1; i >= 0; i --)
            cow[i] = query( cow[i] + 1);
        for( i = 0; i < n; i ++)
            printf( "%d\n", cow[i]);
    }
}

 

 

posted on 2012-07-24 12:27  找回失去的  阅读(318)  评论(0编辑  收藏  举报