码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-12-06 00:07:26      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:

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 51T5,1 \leq N \leq 500001N50000
输出描述
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?i1??是ii前面比p_ip?i??大的数的个数.我们考虑倒着做,当我们处理完ii后面的数,第ii个数就是剩下的数中第f_i-f_{i-1}+1f?i??f?i1??+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;
}
代码

 

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

标签:

原文地址:http://www.cnblogs.com/zxhl/p/5022465.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!