SPOJ 227 Ordering the Soldiers (树状数组)

来源:互联网 发布:靠谱的韩国代购淘宝店 编辑:程序博客网 时间:2024/04/29 08:19

思路:与杭电2852相似,只不过倒着求而已。对于每个给出的数组w,i从n到1逆向,查找当前存在的,且前i个数中sum(i)+w[i==i,sum(i)表示包括i在内的,比i小的数的总个数,w[i]就是前i个数中比i大的数的总和,当然,暴力应该会超时,所以用二分优化一下。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define LL int#define maxn 200005LL c[maxn];int n,a[maxn];bool vis[maxn];void add(int x,int val){    for(; x<=n; x+=(x&-x))        c[x]+=val;}int sum(int x){    int s=0;    for(; x>0; x-=(x&-x))        s+=c[x];    return s;}int main(){    int t,i,l,r,mid,ans;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        memset(c,0,sizeof(c));        memset(vis,0,sizeof(vis));        for(i=1; i<=n; ++i)        {            scanf("%d",&a[i]);            add(i,1);        }        for(i=n; i>=1; --i)        {            l=1,r=n,ans=1;            while(r>=l)            {                mid=(l+r)>>1;                if(sum(mid)+a[i]>=i)                {                    if(!vis[mid])                        ans=mid;                    r=mid-1;                }                else l=mid+1;            }            a[i]=ans;            add(ans,-1);            vis[ans]=1;        }        for(i=1; i<=n; ++i)            if(i==1) printf("%d",a[i]);            else printf(" %d",a[i]);        printf("\n");    }    return 0;}


原创粉丝点击