hdu5592/BestCoder Round #65 树状数组寻找第K大

ZYB‘s Premutation

Memory Limit: 131072/131072 K (Java/Others)

问题描述

ZYBZYB有一个排列PP,但他只记得PP中每个前缀区间的逆序对数,现在他要求你还原这个排列.

(i,j)(i < j)(i,j)(i<j)被称为一对逆序对当且仅当A_i>A_jA?i??>A?j??

输入描述

第一行一个整数TT表示数据组数。

接下来每组数据:

第一行一个正整数NN,描述排列的长度.

第二行NN个正整数A_iA?i??,描述前缀区间[1,i][1,i]的逆序对数.

数据保证合法.

1 \leq T \leq 51≤T≤5,1 \leq N \leq 500001≤N≤50000

输出描述

TT行每行NN个整数表示答案的排列.

输入样例

1
3
0 1 2

输出样例

3 1 2

 题解:设f_if?i??是第ii个前缀的逆序对数,p_ip?i??是第ii个位置上的数,则f_i-f_{i-1}f?i??−f?i−1??是ii前面比p_ip?i??大的数的个数.我们考虑倒着做,当我们处理完ii后面的数,第ii个数就是剩下的数中第f_i-f_{i-1}+1f?i??−f?i−1??+1大的数,用线段树和树状数组可以轻松地求出当前第kk个是11的位置,复杂度O(N \log N)O(NlogN).

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 5e4 + 500;
long long arr[maxn],b[maxn];

#define lowbit(x) ((x)&(-x))

struct BinaryIndexTree
{
    int val[maxn],sz;

    void init(int sz){
        this->sz=sz;
        memset(val , 0 , sizeof(int)*(sz+5));
    }

    void updata(int pos ,int key){
        while(pos<=sz){
            val[pos]+=key;
            pos+=lowbit(pos);
        }
    }

    int prefixsum(int pos){
        int res=0;
        while(pos>0){
            res+=val[pos];
            pos-=lowbit(pos);
        }
        return res;
    }

    int query(int l,int r){
        return prefixsum(r)-prefixsum(l-1);
    }

    //找到第一个大于等于k的位置返回
    //若不存在,返回-1
    int lower_bound(int k){
        if(prefixsum(sz)<k) return -1;
        int l = 1 , r = sz;
        while(l <= r){
            int mid = l + ((r-l)>>1);
            if(prefixsum(mid) < k) l = mid + 1;
            else r = mid - 1;
        }
        return l;
       }

}solver;

int ans[maxn];

int main(int argc,char *argv[]){
    int Case;
    scanf("%d",&Case);
    while(Case--){
        int n;
        scanf("%d",&n);
        solver.init(n);
        for(int i = 1 ; i <= n ; ++ i) scanf("%I64d",arr+i);
        for(int i = 1 ; i <= n ; ++ i) b[i] = arr[i] - arr[i-1];
        for(int i = 1 ; i <= n ; ++ i) solver.updata(i , 1);
        for(int i = n ; i >= 1 ; -- i){
            long long rank = i - b[i];
            int t = solver.lower_bound(rank);
            ans[i] = t;
            solver.updata(t,-1);
        }
        printf("%d",ans[1]);
        for(int i = 2 ; i <= n ; ++ i) printf(" %d",ans[i]);
        printf("\n");
    }
    return 0;
}

代码

时间: 2024-08-27 20:03:40

hdu5592/BestCoder Round #65 树状数组寻找第K大的相关文章

HDU 5249 离线树状数组求第k大+离散化

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1160    Accepted Submission(s): 488 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的

【转载】【树状数组区间第K大/小】

原帖:http://www.cnblogs.com/zgmf_x20a/archive/2008/11/15/1334109.html 回顾树状数组的定义,注意到有如下两条性质: 一,c[ans]=sum of A[ans-lowbit(ans)+1 ... ans];二,当ans=2^k时, c[ans]=sum of A[1 ... ans]; 下面说明findK(k)如何运作:1,设置边界条件ans,ans'<maxn且cnt<=k:2,初始化cnt=c[ans],其中ans=2^k且k

hdu 2985 The k-th Largest Group 树状数组求第K大

The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8353   Accepted: 2712 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to g

zoj 3635 Cinema in Akiba (树状数组求第K大)

Cinema in Akiba Cinema in Akiba (CIA) is a small but very popular cinema in Akihabara. Every night the cinema is full of people. The layout of CIA is very interesting, as there is only one row so that every audience can enjoy the wonderful movies wit

Permutation UVA - 11525(值域树状数组,树状数组区间第k大(离线),log方,log)

Permutation UVA - 11525 看康托展开 题目给出的式子(n=s[1]*(k-1)!+s[2]*(k-2)!+...+s[k]*0!)非常像逆康托展开(将n个数的所有排列按字典序排序,并将所有排列编号(从0开始),给出排列的编号得到对应排列)用到的式子.可以想到用逆康托展开的方法.但是需要一些变化: for(i=n;i>=1;i--) { s[i-1]+=s[i]/(n-i+1); s[i]%=(n-i+1); } 例如:n=3时,3=0*2!+0*1!+3*0!应该变为3=1

POJ2985 The k-th Largest Group[树状数组求第k大值 并查集]

The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8807   Accepted: 2875 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to g

树状数组求第K大(From CLJ)

int ret=0; for(int p=1<<log2[n];p;p>>=1) if(a[ret+p]<=kth) kth-=a[ret+=p]; return ret;

hdu2852 KiKi&#39;s K-Number 树状数组求第k大数

//再求第k大数时只需要getsum(b-1)<getsum(a)+k<=getsum(b) //b就是a的第k大数 //又gesum(b-1)<=getsum(b)则可以用二分查找来做 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=100010; int tree[maxn]; int lowbit(int i) {

树状数组求第K小值 (spoj227 Ordering the Soldiers &amp;&amp; hdu2852 KiKi&#39;s K-Number)

题目:http://www.spoj.com/problems/ORDERS/ and http://acm.hdu.edu.cn/showproblem.php?pid=2852 题意:spoj227:告诉每个位置前面有多少个数比当前位置小,求出原序列.hdu2852:设计一个容器,支持几种操作:增加/删除元素,求容器中比a大的数中第k小的数是多少. 分析:两个题思路都是求数组里面的第K小的数.开始一直在找O(N*logN)的方法,后来发现O(N*logN*logN)也是可以过的...两步:和