• 洛谷 P1168 中位数


     P1168 中位数

    题目描述

    给出一个长度为N的非负整数序列 Ai ,对于所有 1 ≤ k ≤ (N + 1) / 2 

    输出 A1,A3,,A2k - 1的中位数。即前 1,3,5,… 个数的中位数。

    输入输出格式

    输入格式:

    1行为一个正整数 N,表示了序列长度。

    2行包含N个非负整数 Ai (Ai ≤ 10^9) 

     

    输出格式:

    (N + 1) / 2 行,第 i 行为 A1,A3,,A2k - 1 的中位数。

     

    输入输出样例

    输入样例#1: 复制
    7
    1 3 5 7 9 11 6
    输出样例#1: 复制
    1
    3
    5
    6

    说明

    对于 20% 的数据,N ≤ 100

    对于 40% 的数据,N ≤ 3000

    对于 100% 的数据,N ≤ 100000



    这道题乍一看比较简单 其实还是有不少细节的 

    我第一想法是建立主席树 然后每次插数的时候就查询中位数个数那么大的数就好了

    是查询区间第k大的板子嘛 时间复杂度是 $O(nlogn)$ 

    然而这道题O(nlogn2)可以很容易的搞过去 所以在wans的怂恿下写了值域树状数组套二分...写完才发现并不是那么容易的

    第一个问题就是数据是 $ 1e9 $ 范围 显然需要离散化 然后离散化完了还要映射回去 

    然后就是二分的问题 每次二分查找前面的数的个数 如果前面的数的个数包括自己刚好等于中位数的个数

    就先更新答案 然后 r=mid-1  因为有可能我找到了一个空值 就比如 $10101000$ 而我找到的是后面的 直接返回就会出问题

    第二个是当我找到的值大于我中位数的位数时 一样需要更新答案 因为我一个数可能出现多次 我找到的是大于中位数排名的个数

    但是这时候这个排名可能恰好处于这个数所在的区间 但是因为我们计算加上了整个区间的个数  所以这时候也要更新答案

    还有就是 $unique$ 记得 - 1 !!!!!!

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5 + 5;
    int n,m,c[N],val[N],a[N],b[N],ma;
    
    int lowbit(int pos) {
        
        return pos & (-pos);
    }
    
    void add(int pos,int del) {
        
        while(pos <= m) {
            c[pos] += del;
            pos += lowbit(pos);
        }
    }
    
    int query(int pos) {
        
        int ans = 0;
        while(pos >= 1) {
            ans += c[pos];
            pos -= lowbit(pos);
        }
        return ans;
    }
    
    void solve(int num,int pos) {
        
        int l = 1,r = pos,ans = num;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(query(mid) == num) {
                ans = mid;
                r = mid - 1;
            }
            else if(query(mid) < num) l = mid + 1;
            else if(query(mid) > num) ans = mid,r = mid - 1;
        }
        printf("%d
    ",val[ans]);
    }
    
    int main( ) {
        
        scanf("%d",& n);
        for(int i = 1;i <= n;i ++) {
            scanf("%d",& a[i]);
            b[i] = a[i];
        }
        sort(a + 1,a + n + 1);
        m = unique(a + 1,a + n + 1) - a - 1;
        for(int i = 1;i <= n;i ++) {
            int pos = lower_bound(a + 1,a + m + 1,b[i]) - a;
            val[pos] = b[i];
        }
        for(int i = 1;i <= n;i ++) {
            int pos = lower_bound(a + 1,a + m + 1,b[i]) - a;
            add(pos,1);
            int nn = query(m);
            if(i % 2 == 1) solve((nn + 1) / 2,m);
        }
    }
  • 相关阅读:
    三星S11首曝光/2019款iPhone预测价格出炉
    聊聊我用过的电纸书
    阿里云VOD 视频点播(三),后台java接口代码
    阿里云VOD 视频点播(二)、VUE视频上传,视频播放
    阿里云VOD 视频点播(一)、nuxt视频上传,视频播放
    大周末的不休息,继续学习pandas吧,pandas你该这么学,No.7
    杂谈——怎么给CSDN博客加上目录(很详细但是很简单)
    分布式入门之1:Lease机制
    分布式入门之1:Lease机制
    分布式入门之1:Lease机制
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9571543.html
Copyright © 2020-2023  润新知