poj2182

题意:1~n,乱序排列,告诉每个位置的前面的数字中比它小的数的个数,求每个位置的数字是多少

分析:用树状数组来做,第i位如果是1,表示i在数列中的位置已经确定。全部读入到f[]后,从最后向前依次求出是几,因为每次对于未确定的最后一个数来说是可以根据它前面有多少数字比它小以及之前确定的数字(在它后面的数字)而确定它是几的。二分查找当前位置填几,设这个数字为a,应满足树状数组求和结果sum(a),即后面已经填好的比a小的个数,加上f[i],即前面比a小的个数,等于a-1。猜大了则结果大于a-1,猜小了则小于。找到后把树状数组第a位标1。时间复杂度为O((logn)^2 * n)

View Code
#include < iostream >
#include
< cstdlib >
#include
< cstring >
#include
< cstdio >
using namespace std;

#define maxn 8005

int n, f[maxn];
int ar[maxn];
int ans[maxn];

int lowb( int t)
{
return t & ( - t);
}

void add( int i, int v)
{
for (; i < maxn; ar[i] += v, i += lowb(i));
}

int sum( int i)
{
int s = 0 ;
for (; i > 0 ; s += ar[i], i -= lowb(i));
return s;
}

int calspace( int index)
{
return index - sum(index);
}

int binarysearch( int a)
{
int l = 1 ;
int r = n;
int mid;
while (l < r)
{
mid
= (l + r) / 2 ;
int temp = calspace(mid);
if (temp < a)
l
= mid + 1 ;
else
r
= mid;
}
return l;
}

int main()
{
// freopen("t.txt", "r", stdin);
scanf( " %d " , & n);
f[
0 ] = 0 ;
for ( int i = 1 ; i < n; i ++ )
scanf(
" %d " , & f[i]);
for ( int i = n - 1 ; i >= 0 ; i -- )
{
int a = binarysearch(f[i] + 1 );
ans[i]
= a;
add(a,
1 );
}
for ( int i = 0 ; i < n; i ++ )
printf(
" %d\n " , ans[i]);
return 0 ;
}

你可能感兴趣的:(poj)