ZYB有一个排列PPP,但他只记得PPP中每个前缀区间的逆序对数,现在他要求你还原这个排列.
一对数(i,j)当(i<j)时被认为是逆序对。
输入描述
第一行一个整数T表示数据组数。
接下来每组数据:
第一行一个正整数N,描述排列的长度.
第二行N个正整数Ai
,描述前缀区间[1,i]的逆序对数.
数据保证合法.
1≤T≤51 \leq T \leq 51≤T≤5,1≤N≤500001 \leq N \leq 500001≤N≤50000
输出描述
T行每行N个整数表示答案的排列.
输入样例
1
3
0 1 2
输出样例
3 1 2
树的节点保存三个值:左端点a,右端点b,该区间剩下的数字的个数sum。
查询第k大的时候,当k大于右子节点的sum,则查询左子节点第(k-右子节点的sum)大,否则查询右子节点,当左端点等于右端点时返回。
#include <stdio.h>
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
struct Tree
{
int a,b,sum;
}t[200000];
void init(int x,int y,int num)
{
t[num].a=x;
t[num].b=y;
if(x==y)
{
t[num].sum=1;
return;
}
int mid=(x+y)/2;
init(x,mid,num<<1);
init(mid+1,y,(num<<1)+1);
t[num].sum=t[num<<1].sum+t[(num<<1)+1].sum;
}
int query(int x,int num)
{
t[num].sum--;
if(t[num].a==t[num].b) return t[num].a;
if(x>t[(num<<1)+1].sum) return query(x-t[(num<<1)+1].sum,(num<<1));
else return query(x,(num<<1)+1);
}
int main()
{
int n,T;
int a[50005],b[50005];
while(~scanf("%d",&T))
{
while(T--)
{
scanf("%d",&n);
init(1,n,1);
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
}
// for(set<int>::iterator it=se.begin();it!=se.end();it++) printf("%d ",*it);
for(int i=n-1; i>0; i--)
{
int temp=a[i]-a[i-1];
b[i]=query(temp+1,1);
}
b[0]=query(1,1);
for(int i=0; i<n; i++)
if(!i) printf("%d",b[i]);
else printf(" %d",b[i]);
printf("\n");
}
}
}