洛谷 P1168 中位数 堆

题目描述

给出一个长度为 NN 的非负整数序列 A_iAi ,对于所有 1 ≤ k ≤ (N + 1) / 21k(N+1)/2 ,输出 A_1, A_3, …, A_{2k - 1}A1,A3,,A2k1 的中位数。即前 1,3,5,…1,3,5,… 个数的中位数。

输入输出格式

输入格式:

第 11 行为一个正整数 NN ,表示了序列长度。

第 22 行包含 NN 个非负整数 A_i (A_i ≤ 10^9)Ai(Ai109) 。

输出格式:

共 (N + 1) / 2(N+1)/2 行,第 ii 行为 A_1, A_3, …, A_{2k - 1}A1,A3,,A2k1 的中位数。

输入输出样例

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

说明

对于 20\%20% 的数据, N ≤ 100N100 ;

扫描二维码关注公众号,回复: 2293554 查看本文章

对于 40\%40% 的数据, N ≤ 3000N3000 ;

对于 100\%100% 的数据, N ≤ 100000N100000 ;

讲道理一看这题第一反应是暴力模拟,第二眼看到了数据范围,然后滚回去想别的方法,后来觉得插排还行,又觉得单调队列也不错,在一想线段树好像才是真爱,然而,最后这些想法都没用上(好吧其实想不到p.s插排不会写了,sort后遗症233)。。。最后用堆过的来着

先介绍下堆

堆实际上是一棵二叉树,这棵树满足所有的非叶子节点都大于/小于它的儿子,大于的称为大根堆,小于的称为小根堆

下图为一个大根堆

                     233

               12          23

          5        6     7     8

小根堆

                      1

                2           3

           4      5     6       7

可以发现,不论大根堆还是小根堆,堆首都是最值,加上堆是一个logn的复杂度,所以堆广泛运用于top n 问题中

回到本题,对于本题,只开一个堆的话,每次要取出前(n+1)/2-1个元素,取出并输出(n+1)/2个元素然后再把之前取出的元素压回堆中

很明显时间是不够用的,所以考虑开两个堆分别维护,假设左边为大根堆,右边为小根堆,只要大于左边堆首的,就压入右边,这样的话

左边除了堆首,其他元素都小于堆首,右边则全部大于左边的堆首,左边的堆首就是答案了,但是我们发现,要想让左边堆首成为答案,

两个堆的元素差只能为1才行,比如左边有5个元素,右边有2个,这种情况下左边的堆首并不是答案,只有把左边的堆首压入右边,变成

左边4个元素,右边3个,左边的堆首才是答案

完整代码

#include<bits/stdc++.h>
using namespace std;
int read()
{
    long long ans=0;int k=1;char ch=getchar();
    while(ch<'0'||ch>'9')
    {
    if(ch=='-')k=-1;    
    ch=getchar();    
    }
    while(ch>='0'&&ch<='9')
    {
    ans=ans*10+ch-'0';    
    ch=getchar();    
        }
    return ans*k;    
}
//建议用优先队列代替手写堆,方便且不会错 priority_queue
<int,vector<int> > q1;//大根堆 priority_queue<int,vector<int>,greater<int> > q2;//小根堆 int n; int main() { n=read();q1.push(read()); cout<<q1.top()<<endl;//第一个元素直接输出 for(int i=2;i<=n;i++) { int k=read(); if(k>q1.top())q2.push(k);//如果大于左边的堆首,压入右边 else q1.push(k);//否则压入左边 while(abs(q1.size()-q2.size())>1)//如果两边元素差不为1 if(q1.size()>q2.size())q2.push(q1.top()),q1.pop();//左大于右往右压入堆首 else q1.push(q2.top()),q2.pop();//否则往左压入堆首 if (i%2) cout<<(q1.size()>q2.size()?q1.top():q2.top())<<endl;//如果是奇数,输出堆首即可 } return 0; }

参考大佬@ _肖恩Sean_ 题解

猜你喜欢

转载自www.cnblogs.com/pcpcppc/p/9348153.html