• 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_jAi​​>Aj​​
    输入描述
    第一行一个整数TT表示数据组数。
    
    接下来每组数据:
    
    第一行一个正整数NN,描述排列的长度.
    
    第二行NN个正整数A_iAi​​,描述前缀区间[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_ifi​​是第ii个前缀的逆序对数,p_ipi​​是第ii个位置上的数,则f_i-f_{i-1}fi​​fi1​​是ii前面比p_ipi​​大的数的个数.我们考虑倒着做,当我们处理完ii后面的数,第ii个数就是剩下的数中第f_i-f_{i-1}+1fi​​fi1​​+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("
    ");
        }
        return 0;
    }
    代码

    二分法

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N = 1e5+20, M = 30005, mod = 1e9+7, inf = 0x3f3f3f3f;
    typedef long long ll;
    //不同为1,相同为0
    
    int n;
    struct BIT {
        int tree[N] ;
    
        int lowbit(int x) {
            return x&(-x);
        }
        void add(int x, int add, int n) {
            for (; x <= n; x += lowbit(x)) {
                tree[x] += add;
            }
        }
        int sum(int x) {
            int s = 0;
            for (; x > 0; x -= lowbit(x)) {
                s += tree[x];
            }
            return s;
        }
        void clears() {
            memset(tree, 0, sizeof tree);
        }
    }Bit;
    int cal(int x) {
        int l = 1, r = n, ret = -1;
        while(l<=r) {
            int mid = (l+r)>>1;
            int G = Bit.sum(n) - Bit.sum(mid-1);
            if(G>=x) l = mid+1, ret = mid;
            else r = mid-1;
        }
        return ret;
    }
    int main() {
        int T,b[N],a[N],ans[N];
        scanf("%d",&T);
        while(T--) {
            scanf("%d",&n);
            for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i] = a[i] - a[i-1];
            Bit.clears();
            for(int i=1;i<=n;i++) Bit.add(i,1,n);
            int pos = n - b[n];
            ans[n] = pos;
            Bit.add(pos,-1,n);
            for(int i = n-1;i >= 1;i--) {
                pos = cal(b[i]+1);
                ans[i] = pos;
                Bit.add(pos,-1,n);
            }
            for(int i=1;i<n;i++) {
                printf("%d ",ans[i]);
            }
            printf("%d
    ",ans[n]);
        }
        return 0;
    }
  • 相关阅读:
    vscode远程开发
    iframe父子组件传值
    react项目地址栏添加包名
    记一次lombok踩坑记
    Android Adb修改系统时区 NTP 服务器
    ES文件浏览器4.1.9.7.4任意文件浏览漏洞
    SUID提权之python的os.setuid(0)提权
    PHP-8.1.0-dev 后门命令执行
    将博客搬至CSDN
    零基础快速上手HarmonyOS开发1---为什么要学习HarmonyOS?如何能快速上手?HarmonyOS架构解析、和Android深度对比
  • 原文地址:https://www.cnblogs.com/zxhl/p/5022465.html
Copyright © 2020-2023  润新知