题意: 有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]); } }