spoj 227 Ordering the Soldiers——树状数组

有n个点,标号1到n,给定数组b[i]表示i前面比a[i]小的点的个数,求a[]数组。

我们倒着扫b数组,将符合条件的最大的数插入a数组相应的位置,就得解了。但是朴素查找需要很多时间,就需要用数状数组了。维护一个c数组,sum(i)表示现在有几个数字不大于i,因为sum(i)是有序的,所以我们每次查找的时候就用二分查找就行了,在找到这个点以后,就从c数组中删去。总的复杂度为O(n * logn * logn)

先开始二分写搓了,改了老半天,唉,二分还是太弱了阿。。

2011-10-03 15:07:11 RosieYe Ordering the Soldiers accepted
edit  run
2.54 4.9M

C++

4.3.2

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 200000+10

int step[MAXN];
int ans[MAXN];
int c[MAXN];
int n;

int lowbit(int x)
{
return x&(-x);
}

void update(int x,int value)
{
while(x<=n)
{
c[x]+=value;
x+=lowbit(x);
}
}

int sum(int x)
{
int s=0;
while(x>0)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}

int main(void)
{
int T;
scanf("%d",&T);
while(T--)
{
memset(c,0,sizeof(c));
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&step[i]);
update(i,1);//初始化数状数组
}
for(i=n;i>=1;i--)
{
int goal=i-step[i];
int low=1;
int high=n;
while(high>=low)
{
int mid=(high+low)/2;
int s=sum(mid);//logn地求sum的值
if(s>=goal)
{
high=mid-1;
}
else if(s<goal) low=mid+1;
}
update(low,-1);
ans[i]=low;
}
for(i=1;i<=n;i++)
{
if(i==n)
printf("%d\n",ans[i]);
else printf("%d ",ans[i]);
}
}
return 0;
}

你可能感兴趣的:(order)