//线段树 //题意:给定数列的顺序数,进而确定数列的排列 //思路:逆向思考,对给定的N个数,从第N个数入手,如果他的顺序数是k,则说明他在1~N中排第k+1位 //确定一个元素的位置K后,从1~N这个序列中删除K //之后计算第N-1个数,同理在1~N-1个数中看他排第几位,确定他的位置 //EXAMPLE: //序列:1,2,3,4 //顺序数:1,1,2 //3+1 = 4,在1,2,3,4中排第4位,ans[4] = 4,在1,2,3,4中删除4,剩1,2,3 //1+1 = 2,在1,2,3中排第2位,ans[3] = 2,删除2,剩1,3 //1+1 = 2,在1,3中排第2位,ans[2] = 3,删除3,剩1 //以此类推,这一个过程可以用搜索来完成O(n^2),通过线段树优化可到O(nlgn) #include<iostream> using namespace std; struct Seg { int l,r,key;//key值表示[l,r]区间内未被确定的元素个数 }segTree[20000]; int arr[8010]; int n,N; void buildTree(int fa,int l,int r)//构造线段树 { segTree[fa].l = l; segTree[fa].r = r; segTree[fa].key = r - l + 1; if(l == r) return; int mid = (l + r) >> 1; buildTree(2 * fa,l,mid); buildTree(2 * fa + 1,mid + 1,r); } int query(int fa,int k)//要查找排第K位的数 { --segTree[fa].key;//顺着查找方向逐步减少key值,等效于在1~N中删除某点的值 if(segTree[fa].l == segTree[fa].r)//查找到叶子节点,则返回改元素 return segTree[fa].l; if(segTree[2 * fa].key >= k)//如果左儿子的KEY >= k,说明要查找的元素必定在左子树 return query(2 * fa,k); else return query(2 * fa + 1,k - segTree[2 * fa].key);//否则说明要查找的元素在右子树 //注意这个过程中的k - segTree[2*fa].key //K减去左子树的KEY值,然后再到右子树中去查找 } int main() { //freopen("in.txt","r",stdin); scanf("%d",&n); buildTree(1,1,n); arr[1] = 0; for(int i = 2;i <= n;++i) scanf("%d",&arr[i]); for(int i = n;i >= 1;--i)//逆序处理 arr[i] = query(1,arr[i] + 1); for(int i = 1;i <= n;++i) printf("%d/n",arr[i]); return 0; }