问题描述
ZYB有一个排列P,但他只记得P中每个前缀区间的逆序对数,现在他要求你还原这个排列. (i,j)(i<j)被称为一对逆序对当且仅当Ai>Aj
输入描述
第一行一个整数T表示数据组数。 接下来每组数据: 第一行一个正整数N,描述排列的长度. 第二行N个正整数Ai,描述前缀区间[1,i]的逆序对数. 数据保证合法. 1≤T≤5,1≤N≤50000
输出描述
T行每行N个整数表示答案的排列.
输入样例
1 3 0 1 2
输出样例
3 1 2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=50000+100;
int a[maxn],pre[maxn],c[maxn],b[maxn];
int n;
void add(int x,int d)
{
while(x<=n) {
c[x]+=d;
x+=x&(-x);
}
}
int sum(int x)
{
int ans=0;
while(x>0) {
ans+=c[x];
x-=x&(-x);
}
return ans;
}
int main()
{
int t,i,j,l,r,num;
scanf("%d",&t);
while(t--) {
memset(c,0,sizeof(c));
scanf("%d",&n);
pre[0]=0;
for(i=1;i<=n;i++) {
scanf("%d",&pre[i]);
a[i]=pre[i]-pre[i-1];
add(i,1);
}
for(i=n;i>0;i--) {
l=1;r=n;
while(l<=r) {
int mid=(l+r)>>1;
num=sum(n)-sum(mid);
if(num<=a[i]) r=mid-1;
else l=mid+1;
}
b[i]=l;
add(l,-1);
}
for(i=1;i<=n;i++) {
printf("%d",b[i]);
if(i!=n) printf(" ");
}
printf("\n");
}
return 0;
}