BC 65 ZYB's Premutation (线段树+二分搜索)

题目简述:有一个全排列,一直每个前缀区间的逆序对数,还原这个排列。

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?'\n':' ');
77     }
78     return 0;
79 }

 

posted @ 2015-12-06 20:33  御心飞行  阅读(166)  评论(0编辑  收藏  举报