HDU 5592 ZYB's Game 树状数组+二分

Posted 00isok

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 5592 ZYB's Game 树状数组+二分相关的知识,希望对你有一定的参考价值。

<题目链接>

题目大意:

给你一个由1~n,n个数组成的序列,给出他们每个的前缀逆序数,现在要求输出这个序列。

解题分析:

由前缀逆序数很容易能够得到每个数的逆序数。假设当前数是i,它前面比它小的数为a[i]( i - 1 - i的逆序数即可),我们不难知道,i在前i个数中是第i+1大的。然后我们从后往前考虑,每次都能确定一个位置的数的大小,根据当前位置i的数在 1~i 的数的大小,我们用二分查找快速聪当前还未分配的数中给它分配相应大小的数值,然后将这个数值从可分配的数中剔除,防止对前面的数造成影响(相当于每次只考虑i前面的数,i后面的数都已经确定好了数值)。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 5e4+5;
 6 int n;
 7 int a[N],tr[N],ans[N];
 8 inline int lowbit(int x){return x&(-x);}
 9 void add(int x,int val){
10     for(int i=x;i<=N;i+=lowbit(i))
11         tr[i]+=val;
12 }
13 int sum(int x){
14     int ans=0;
15     for(int i=x;i>0;i-=lowbit(i))
16         ans+=tr[i];
17     return ans;
18 }
19 int Binary(int k){
20     int lt = 1, rt = n, mid, t;
21     while (lt+1 < rt){
22         mid = (lt+rt)>>1;
23         t = sum(mid);    
24         if (t >= k) rt = mid;
25         else lt = mid;
26     }
27     if (sum(lt) == k) return lt;
28     else return rt;
29 }
30 void solve(){
31     for(int i=1;i<=n;i++)add(i,1);
32     for(int i=n;i>0;i--){     //从后往前,逐渐分配可供选择的数
33         ans[i]=Binary(a[i]+1);  //在当前可供选择的数中,挑选第a[i]+1大的数
34         add(ans[i],-1);   //因为是根据第i个数是前i个数中第a[i]+1大的来确定位置的,所以要消除i后面的所有元素的影响
35     }
36     for(int i=1;i<=n;i++)
37         printf("%d%s",ans[i],i==n?"
":" ");
38 }
39 int main(){
40     int T;scanf("%d",&T);while(T--){
41         scanf("%d",&n);
42         int pre=0, now;
43         for(int i=1;i<=n;i++){
44             scanf("%d",&now);
45             a[i]=i-1-(now-pre);
46             pre=now;
47         }
48         memset(tr,0,sizeof(tr));
49         solve();
50     }
51 }

 

 

2018-12-15

以上是关于HDU 5592 ZYB's Game 树状数组+二分的主要内容,如果未能解决你的问题,请参考以下文章

BestCoder Round #65 hdu5592 5593 5594

hdu 6468 zyb的面试

hdu5592 倒序求排列+权值线段树

BestCoder Round #66 (div.2) hdu5592

ZYB loves Xor I HDU - 5269 字典树

HDU 1517: kiki's game