Description
对于一个集合S={1,2,3,...N}的任一排列a1、a2、a3、... aN,我们定义ai的逆序数为∑(aj>ai | j<i),即排在ai前的所有比ai大的数的个数。我们把每个数的逆序数按下标排出就构成排列a1、a2、a3、... aN的一个逆序排列。比如排列 3 1 2的逆序排列为1 1 0(从左往右依次是1的逆序数、2的逆序数、3的逆序数)。
现在我们给出一个排列的逆序排列,请求出原排列。
Input
输入包含多组测试数据。
首先第一行输入一个数T(T<=10),表示总共有T组测试数据。
接下来是每组测试数据,第一行是一个数N(N<=100000),表示是N个数的排列。然后接下来一行是N个数字(数字之间用空格隔开<=N),表示这个排列。
Output
首先,输出Case #X:其中X代表是第X组数据(具体格式参照样例)。
然后,输出原排列(数字之间用一个空格隔开、注意行末无空格)。
Sample Input
3
2
1 0
3
1 1 0
4
3 2 1 0
Sample Output
Case #1:
2 1
Case #2:
3 1 2
Case #3:
4 3 2 1
Hint
巨大的输入输出,推荐printf,scanf
Source
humanjustic
思路:
线段树,开始一直想用线段树,却想不到好的方法,最后终于想到了。。。
代码:
#include<iostream>
using namespace std;
#define N 100005
struct Treenode{
int l;
int r;
int v;
int c;
};
Treenode arr[N*3];
int ans[N];
void bulid(int l,int r,int k)
{
arr[k].l = l;
arr[k].r = r;
arr[k].c = 0;
if(l==r)
return;
int mid = (l+r)>>1;
bulid(l,mid,2*k);
bulid(mid+1,r,2*k+1);
}
void insert(int d,int v,int k)
{
if(arr[k].l==arr[k].r)
{
arr[k].v = v;
arr[k].c+=1;
ans[d] = v;
return;
}
int mid = (arr[k].l+arr[k].r)>>1;
if(d+arr[2*k].c>mid)
insert(d+arr[2*k].c,v,2*k+1);
else
insert(d,v,2*k);
arr[k].c = arr[2*k].c+arr[2*k+1].c;
}
int main()
{
int t,cnt = 1;
scanf("%d",&t);
while(t--)
{
int n,tmp;
scanf("%d",&n);
bulid(1,n,1);
for(int i=1;i<=n;i++)
{
scanf("%d",&tmp);
insert(tmp+1,i,1);
}
printf("Case #%d:\n",cnt++);
for(int i=1;i<n;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
}