题目描述:
你知道有一个1~n的排列,但具体排列你不知道。现在给出1~n每个前缀的逆序数对数,让你还原这个排列
题目分析:
我们倒着处理
在i位置的前缀逆序对个数为X,在i-1位置的前缀逆序对个数为Y
那么i前面就有 X-Y 个比他大的数
然后在权值线段树中查询排名即可
操作有:排名查询,单点修改
题目链接:
Ac 代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#define il inline
const int maxm=1e6+100;
int st[maxm],n;
int rev[maxm],ans[maxm];
il void update(int o)
{
st[o]=st[(o<<1)]+st[(o<<1)|1];
}
void build(int o,int l,int r)
{
if(l>=r)
{
st[o]=1;
return;
}
int mid=(l+r)>>1;
build((o<<1),l,mid);
build((o<<1)|1,mid+1,r);
update(o);
}
int ask(int o,int l,int r,int rank)
{
if(l>=r) return l;
int mid=(l+r)>>1;
if(rank<=st[(o<<1)]) return ask((o<<1),l,mid,rank);
else return ask((o<<1)|1,mid+1,r,rank-st[(o<<1)]);
}
void change(int o,int l,int r,int ind,int flag)
{
if(l>=r)
{
st[o]+=flag;
return;
}
int mid=(l+r)>>1;
if(ind<=mid) change((o<<1),l,mid,ind,flag);
else change((o<<1)|1,mid+1,r,ind,flag);
update(o);
}
il void work()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&rev[i]);
build(1,1,n);
for(int i=n;i>=1;i--)
{
ans[i]=ask(1,1,n,i-(rev[i]-rev[i-1])),change(1,1,n,ans[i],-1);
//printf("%d\n",i-(rev[i]-rev[i-1]));
}
for(int i=1;i<=n;i++)
{
printf("%d",ans[i]);
i==n?printf("\n"):printf(" ");
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--) work();
return 0;
}