思路:与杭电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 200005
LL 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;
}