额,昨天题目太难,所以没写总结,惭愧。最近老考线段树。
题目大意:给一段序列的逆序对前缀和,现在要求出这个序列;
分析:,不难看出从后往前推,i-p[i]就是这个数在前面排第几大,于是我们只需要找出序列中第几大的位置,放进去打个标记就好了,线段树维护。
# include <iostream>
# include <cstdio>
# include <cmath>
# include <list>
# include <cstring>
# include <map>
# include <ctime>
# include <algorithm>
# include <queue>
using namespace std;
typedef long long ll;
int read(){
register int f=1,i=0;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}
return f*i;
}
int tr[100005<<2];
ll n,m,p[100005],ans[100005];
struct seg
{
inline void change(int k){
tr[k]=tr[k<<1]+tr[k<<1|1];
}
inline 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);
change(k);
}
inline int query(int k,int l,int r,int x){
if(l==r){tr[k]=0;return l;}
int mid=l+r>>1,tmp;
if(x<=tr[k<<1]) tmp=query(k<<1,l,mid,x);
else tmp=query(k<<1|1,mid+1,r,x-tr[k<<1]);
change(k);return tmp;
}
}Seg;
int main()
{
n=read();
for(int i=1;i<=n;++i) p[i]=read();
for(int i=n;i;--i) p[i]-=p[i-1];
Seg.build(1,1,n);
for(int i=n;i;--i)
ans[i]=Seg.query(1,1,n,i-p[i]);
for(int i=1;i<=n;++i)
cout<<ans[i]<<" ";
}