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?"\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 【树状数组】+【二分】

原文地址:https://www.cnblogs.com/00isok/p/10123777.html

时间: 2024-08-27 19:43:58

HDU 5592 ZYB's Game 【树状数组】+【二分】的相关文章

HDU 5592 ZYB&#39;s Premutation(树状数组+二分)

题意:给一个排列的每个前缀区间的逆序对数,让还原 原序列. 思路:考虑逆序对的意思,对于k = f[i] - f[i -1],就表示在第i个位置前面有k个比当前位置大的数,那么也就是:除了i后面的数字之外,它是在剩下的数字当中第k+1大的. 知道这个之后,可以用树状数组来帮助找出剩下的数中第k大的数,刚开始我们可以让1-n中每个元素都标记为1,那么他们的前缀和就代表它是第几小.所以,我们可以对于他们的和来二分快速寻找第k大数.其实在树状数组里面是按照第(i-k)小来找的.找完之后要删除这个元素的

hdu 5592 ZYB&#39;s Game 树状数组

ZYB's Game Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5592 Description ZYB has a premutation P,but he only remeber the reverse log of each prefix of the premutation,now he ask you to restore the premutation

HDU 2852 KiKi&#39;s K-Number (树状数组 &amp;&amp; 二分)

题意:给出对容器的总操作次数n, 接下来是这n个操作.这里对于一个容器提供三种操作, 分别是插入.删除和查找.输入0  e表示插入e.输入1  e表示删除e,若元素不存在输出No Elment!.输入2  e  k表示查找比e大且第k大的数, 若不存在则输出Not Find! 分析:这里考虑树状数组做的原因是在第三个操作的时候, 只要我们记录了元素的总数, 那通过求和操作, 便能够高效地知道到底有多少个数比现在求和的这个数要大, 例如 tot - sum(3)就能知道整个集合里面比3大的数到底有

hdu 3015 Disharmony Trees (离散化+树状数组)

Disharmony Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 663    Accepted Submission(s): 307 Problem Description One day Sophia finds a very big square. There are n trees in the square. T

HDU 3584 Cube (三维 树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3584 Cube Problem Description Given an N*N*N cube A, whose elements are either 0 or 1. A[i, j, k] means the number in the i-th row , j-th column and k-th layer. Initially we have A[i, j, k] = 0 (1 <= i, 

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU 2852 KiKi&#39;s K-Number【 树状数组 二分 】

题意:给出m个操作,0:是增加一个数,add(x,1)1:是删除一个指定的数,这个是看sum(x) - sum(x-1)是否为0,为0的话则不存在,不为0的话,则add(x,-1)2:是查询比x大的数中第k大的数,先求出比x小的个数s,假设比x大的数中第k大的数为y,那么比y小的个数有s+k个二分y的值来找 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath&g

HDU 2852 KiKi&#39;s K-Number(树状数组+二分)

KiKi's K-Number Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2598    Accepted Submission(s): 1199 Problem Description For the k-th number, we all should be very familiar with it. Of course,t

HDU 6447 - YJJ&#39;s Salesman - [树状数组优化DP][2018CCPC网络选拔赛第10题]

Problem DescriptionYJJ is a salesman who has traveled through western country. YJJ is always on journey. Either is he at the destination, or on the way to destination.One day, he is going to travel from city A to southeastern city B. Let us assume th

ZOJ 3635 树状数组+二分

这题那时怎么想就是想不出来--而且今晚没有多大状态,自己都晕了--一题没做出来-- baoge解释好久才懂--唉--线段树,树状数组用得还是不够熟啊-- WA了二发,才知道二分错了,二分好久不用,老是出错了现在-- #include<iostream> #include<cstring> #include<string> #include<cstdio> #define sca(a) scanf("%d",&a) #define