blog题解鸽了许久了。。本来说好的切一题写一个题解的说
一个$1 sim n$数列,已知每个数前面比他小的数个数,试确定该序列。
相当的一道水题。可以发现数列最后一个数是首先可以确定下来的。然后把这个数扔掉,看数列倒数第二个数前面有多少更小的其实就是目前剩下的数中的排名。相当于有一颗$n$个点的$1 sim n$的平衡树,每次查一个排名,找出这个数,并删掉。但是并不想打平衡树。因为这题的操作只涉及简单的删除和查rank操作,可以考虑用BIT代替平衡树。具体是因为BIT本身就是具有树形二分结构的,画图应该可以感觉出来。$C[i]$表示值为i的数有几个(本题中最多$1$个,有些题还要离散化这个$i$),前缀和维护,查rank的时候不断查$C[x]$并二分下去,和平衡树就类似了。有点难讲,不过真的很好理解。
没了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #define dbg(x) cerr<<#x<<" = "<<x<<endl 8 #define _dbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl 9 using namespace std; 10 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 11 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 12 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 13 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 14 template<typename T>inline T read(T&x){ 15 x=0;char c;int f=0;while(!isdigit(c=getchar()))if(c=='-')f=1; 16 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 17 } 18 const int N=100000+7; 19 int C[N],a[N]; 20 int n; 21 #define lowbit(x) x&(-x) 22 inline void Update_add(int x,int k){for(;x<=n;x+=lowbit(x))C[x]+=k;} 23 inline int Query_sum(int x){int ret=0;for(;x;x-=lowbit(x))ret+=C[x];return ret;} 24 inline int Query_kth(int x){ 25 int i=1<<__lg(n); 26 while((lowbit(i))^1){ 27 if(x<=C[i])i-=((lowbit(i))>>1); 28 else x-=C[i],i+=((lowbit(i))>>1); 29 while(i>n)i-=((lowbit(i))>>1); 30 } 31 return C[i]^x?i+1:i; 32 } 33 34 int main(){//freopen(".in","r",stdin);freopen(".out","w",stdout); 35 read(n);a[1]=1; 36 for(register int i=2;i<=n;++i)read(a[i]),++a[i]; 37 for(register int i=1;i<=n;++i)C[i]=lowbit(i); 38 for(register int i=n;i;--i){ 39 int x=Query_kth(a[i]); 40 Update_add(x,-1),a[i]=x; 41 } 42 for(register int i=1;i<=n;++i)printf("%d ",a[i]); 43 return 0; 44 }