题目简述:有一个全排列,一直每个前缀区间的逆序对数,还原这个排列。
fi记录逆序对数,pi记录该位置数值,则k=fi-f(i-1)表示前i-1个数比pi大的数的个数,那么只要在剩余元素求出按大小顺序第i-k个数字即可。
线段树+二分搜索,线段树bit[i]记录i的在剩余元素的排名顺序。
1 /******************************* 2 3 Date : 2015-12-06 19:49:59 4 Author : WQJ (1225234825@qq.com) 5 Link : http://www.cnblogs.com/a1225234/ 6 Name : 7 8 ********************************/ 9 #include <iostream> 10 #include <cstdio> 11 #include <algorithm> 12 #include <cmath> 13 #include <cstring> 14 #include <string> 15 #include <set> 16 #include <vector> 17 #include <queue> 18 #include <stack> 19 #define LL long long 20 using namespace std; 21 int a[5000+10]; 22 int bit[5000+10]; 23 int ans[5000+10]; 24 int n; 25 int lowbit(int i) 26 { 27 return i&-i; 28 } 29 int sum(int i) 30 { 31 int s=0; 32 while(i>0) 33 { 34 s+=bit[i]; 35 i-=lowbit(i); 36 } 37 return s; 38 } 39 void add(int i,int a) 40 { 41 while(i<=n) 42 { 43 bit[i]+=a; 44 i+=lowbit(i); 45 } 46 } 47 int main() 48 { 49 freopen("in.txt","r",stdin); 50 int i,j; 51 int T; 52 scanf("%d",&T); 53 while(T--) 54 { 55 scanf("%d",&n); 56 for(i=1;i<=n;i++) scanf("%d",&a[i]); 57 a[0]=0; 58 memset(bit,0,sizeof(bit)); 59 for(i=1;i<=n;i++) add(i,1); /*用树状数组记录i的大小排名*/ 60 for(i=n;i>=1;i--) 61 { 62 int temp=a[i]-a[i-1]; 63 temp=i-temp; //排在第temp的数 64 int l=1,r=n,mid; 65 int k=r; 66 while(r>=l) 67 { 68 mid=(r+l)/2; 69 if(sum(mid)>=temp) {k=mid;r=mid-1;} 70 else l=mid+1; 71 } 72 ans[i]=k; 73 add(ans[i],-1); 74 } 75 for(i=1;i<=n;i++) 76 printf("%d%c",ans[i],i==n?' ':' '); 77 } 78 return 0; 79 }