题意:给出一个数组每个元素的逆序数,还原这个数组(序号为1-n)
思路:还是从逆序开始处理,对于每个位置i,如果逆序数是a[i],并且我们不考虑i之后的位置,则第i个位置的序号本应该是a[i]+1,但是如果i之后的位置还存在k个小于等于a[i]+1的数,则位置i需要改为 a[i]+1+k。
因此,我们从后面往前处理,每次处理只需要看之前的操作(对应操作编号i到n)是否确定了小于等于原本应该填的数(a[i]+1), 如果是则i位置应填的数X增加一 ,变为a[i]+1+1...以此类推
线段树的节点维护当前区间已被确定的节点数,我们只需要判断 sum[左区间]+a[i]+1<= mid,便可知道进左区间还是右了,
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
#define ptf(ar1,ar2) printf("ar1:%d\n",ar2);
const long long maxn = 8005;
struct tree
{
int sum[maxn*4];
void init()
{
memset(sum,0,sizeof(sum));
}
void pushup(int rt)
{
sum[rt]= (sum[rt<<1]+sum[rt<<1|1]);
}
void update(int l,int r,int num,int rt,int val)
{
if (l==r&&l==num )
{
sum[rt]=val;
return ;
}
int mid=(l+r)/2;
if (num<=mid)
update(l,mid,num,rt<<1,val);
else
update(mid+1,r,num,rt<<1|1,val);
pushup(rt);
}
int query(int num,int l,int r,int rt) //查询大于等于val的第一个位置
{
if (l==r)
{
sum[rt]=1;
return l;
}
int mid=(l+r)>>1;
int ret=-1;
if (sum[rt<<1]+num<=mid) //应该插入的位置为sum[rt<<1]+num
ret=query(num,l,mid,rt<<1);
else
ret=query(num+sum[rt<<1],mid+1,r,rt<<1|1);//如果左区间不满足,则应该插入sum[rt]+num
pushup(rt);
return ret;
}
};
tree tp;
struct node
{
int l,r,id;
int num;
};
int tm[8005];
int ans[8005];
int main( )
{
int i;
int x;
int n,h,w;
int l,r;
int cun=0;
scanf("%d",&n);
for (i=2; i<=n; i++)
{
scanf("%d",&tm[i]);
}
for (i=n;i>=2;i--)
{
int ret=tp.query( tm[i]+1,1,n,1);
//ptf(1,2);
ans[i]=ret;
}
int sum=0;
for (i=2; i<=n; i++)
if (ans[i]) sum+=ans[i];
ans[1]=n*(n+1)/2-sum;
for (i=1; i<=n; i++)
{
printf("%d\n",ans[i]);
}
return 0;
}