题意:给出一个数组每个元素的逆序数,还原这个数组(序号为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; }