题目大意:
对于一个1到n的排列,若知道每一位的逆序数(第i位a[i]的逆序数就是a[1]~a[i-1]中比a[i]大的数的个数),则能求出原排列。
现在对于排列{a[i]},给出{p[i]}。p[i]表示a[1]~a[i]的逆序数和。请你求出原排列。(1<=n<=100000)
解题思路:
先求出每个数的逆序数,仍设为p[i],倒着确定,那对于最后一个未确定的数a[i]来说,它前面有p[i]个比它大的数,所以他就是剩下未确定的中的第i-p[i]小的数,用权值线段树维护即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
ll getll()
{
ll i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=i*10+c-'0';
return i*f;
}
const int N=100005;
int n,a[N],tr[N<<2];
ll p[N];
void build(int k,int l,int r)
{
if(l==r)
{
tr[k]=1;
return;
}
int mid=l+r>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
tr[k]=tr[k<<1]+tr[k<<1|1];
}
int query(int k,int l,int r,int num)
{
if(l==r)
{
tr[k]=0;
return l;
}
int mid=l+r>>1,res;
if(num<=tr[k<<1])res=query(k<<1,l,mid,num);
else res=query(k<<1|1,mid+1,r,num-tr[k<<1]);
tr[k]=tr[k<<1]+tr[k<<1|1];
return res;
}
int main()
{
//freopen("premu.in","r",stdin);
//freopen("premu.out","w",stdout);
n=getint();
for(int i=1;i<=n;i++)p[i]=getll();
for(int i=n;i;i--)p[i]-=p[i-1];
for(int i=1;i<=n;i++)p[i]=i-p[i];
build(1,1,n);
for(int i=n;i;i--)
a[i]=query(1,1,n,p[i]);
for(int i=1;i<=n;i++)
cout<<a[i]<<' ';
return 0;
}