平衡树 Number
问题 B: Number
时间限制: 1 Sec 内存限制: 256 MB题目描述
一个排列,求出了 a 数组,其中 ai 表示第 i 个数左边有多少个数比它小
计算出原来的排列
输入
第一行输入 n 接下来 n - 1 个整数 ai,下标从 2 开始
输出
输出 n 个整数表示原排列
样例输入
51210
样例输出
24531
提示
对于 20% 的数据满足:1 ≤ n ≤ 10
对于 50% 的数据满足:1 ≤ n ≤ 1000
对于 100% 的数据满足,1 ≤ n ≤ 100000
保证解存在
做法有很多:一,二分加树状数组;
二,链表(TLE一半N^2效率)
三,平衡树。
最后一个点能得到它在整个数组中的排名,得知自己的号,扣掉了一个数,因此第n-1个点也知道了,
那么如何优化找排名的过程——平衡树。
先推进去1~n,在一个一个删。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<set> using namespace std; int read() { int sum=0,f=1;char x=getchar(); while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();} while(x>='0'&&x<='9'){sum=sum*10+x-'0';x=getchar();} return sum*f; } int n,a[1000005],b[1000005],root,hh; struct tree { int l,r,size,tot,h,rd; } t[100005]; void l_swap(int &root) { int k=t[root].r; t[root].r=t[k].l; t[k].l=root; t[k].size=t[root].size; t[root].size=t[t[root].l].size+t[t[root].r].size+t[root].tot; root=k; } void r_swap(int &root) { int k=t[root].l; t[root].l=t[k].r; t[k].r=root; t[k].size=t[root].size; t[root].size=t[t[root].l].size+t[t[root].r].size+t[root].tot; root=k; } void build(int &root,int k) { if(!root) { root=++hh; t[root].h=k; t[root].size=t[root].tot=1; t[root].rd=rand(); return; } t[root].size++; if(t[root].h==k)t[root].tot++; else { if(t[root].h>k) { build(t[root].l,k); if(t[t[root].l].rd<t[root].rd); r_swap(root); } else { build(t[root].r,k); if(t[t[root].r].rd<t[root].rd) l_swap(root); } } } void del(int &root,int k) { if(!root)return; if(t[root].h==k) { if(t[root].tot>1) { t[root].tot--; t[root].size--; return; } if(t[root].l*t[root].r==0) root=t[root].l+t[root].r; else { if(t[t[root].l].rd<t[t[root].r].rd) r_swap(root); else l_swap(root); del(root,k); } } else { t[root].size--; if(k>t[root].h)del(t[root].r,k); else del(t[root].l,k); } } int Q(int &root,int k) { if(!root)return 0; if(t[t[root].l].size+1<=k&&t[t[root].l].size+t[root].tot>=k) return t[root].h; if(t[t[root].l].size>=k) return Q(t[root].l,k); if(t[t[root].l].size<k) return Q(t[root].r,k-t[root].tot-t[t[root].l].size); } int main() { //freopen("number.in","r",stdin); // freopen("number.out","w",stdout); n=read(); build(root,1); for(int i=2;i<=n;i++) { a[i]=read(); build(root,i); } for(int i=n;i>=1;i--) { int k=Q(root,a[i]+1); b[i]=k; del(root,k); } for(int i=1;i<=n;i++)printf("%d\n",b[i]); }