poj 2182 树状数组

倒着考虑,如果最后一只牛的前面有x只比它小,那么它就是第x+1只牛,从序列中去掉它。对倒数第二只牛来说也同理。可以用树状数组来维护前缀和,一开始每个位置都是1,求出结果的牛从树状数组中删掉(update成0),即可获得答案。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 
 6 const int N = 8001;
 7 int c[N];
 8 int r[N];
 9 int ans[N];
10 int n;
11 
12 int lb( int i )
13 {
14     return i & -i;
15 }
16 
17 void update( int i, int v )
18 {
19     while ( i <= n )
20     {
21         c[i] += v;
22         i += lb(i);
23     }
24 }
25 
26 int kth( int k )
27 {
28     int ans = 0, cnt = 0;
29     for ( int i = 12; i >= 0; i-- )
30     {
31         ans += ( 1 << i );
32         if ( ans >= n || cnt + c[ans] >= k )
33         {
34             ans -= ( 1 << i );
35         }
36         else
37         {
38             cnt += c[ans];
39         }
40     }
41     return ans + 1;
42 }
43 
44 int main ()
45 {
46     while ( scanf("%d", &n) != EOF )
47     {
48         memset( c, 0, sizeof(c) );
49         for ( int i = 1; i <= n; i++ )
50         {
51             update( i, 1 );
52         }
53         r[1] = 1;
54         for ( int i = 2; i <= n; i++ )
55         {
56             scanf("%d", &r[i]);
57             r[i]++;
58         }
59         for ( int i = n; i >= 1; i-- )
60         {
61             ans[i] = kth( r[i] );
62             update( ans[i], -1 );
63         }
64         for ( int i = 1; i <= n; i++ )
65         {
66             printf("%d
", ans[i]);
67         }
68     }
69     return 0;
70 }
原文地址:https://www.cnblogs.com/huoxiayu/p/4764440.html