首页 > 技术文章 > P1168 中位数 (优先队列,巧解)

Kv-Stalin 2018-05-26 16:29 原文

题目描述

给出一个长度为N的非负整数序列A[i],对于所有1 ≤ k ≤ (N + 1) / 2,输出A[1], A[3], …, A[2k - 1]的中位数。即前1,3,5,……个数的中位数。

输入输出格式

输入格式:

 

输入文件median.in的第1行为一个正整数N,表示了序列长度。

第2行包含N个非负整数A[i] (A[i] ≤ 10^9)。

 

输出格式:

 

输出文件median.out包含(N + 1) / 2行,第i行为A[1], A[3], …, A[2i – 1]的中位数。

 

输入输出样例

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

说明

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

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

对于100%的数据,N ≤ 100000.

 

Solution

  看到是中位数,一开始想用线段树做,结果发现一点都不好处理.

  于是看到别人的思路,蛮巧妙的.

        1) 首先,既然是中位数,我们想一想,可不可以在维护的时候把它们这些元素就分成两半呢?

     一半存小一点的,一半存大一点的.

        2) 既然是要这样存数,那么我们可以直接用一个大根堆和一个小根堆来维护.

        3) 然后还有就是,我们需要保证这两个堆的元素个数相差1,这样直接让元素多的那个堆的堆顶输出即可.

 

  然后我直接用的STL 里面的堆.

 

代码

  

#include<bits/stdc++.h>
using namespace std;
const int maxn=100008;
int c[maxn],n;
priority_queue <int,vector<int> > q2;
priority_queue <int,vector<int>,greater<int> > q1;

int main()
{
    scanf("%d",&n);
    scanf("%d",&c[1]);
    if(n%2==0)n--;
    //如果是偶数,我最后一个没必要处理.
    cout<<c[1]<<endl;
    q2.push(c[1]);
    for(int i=2;i<=n;i+=2)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(x>y) swap(x,y);
        //保证小一点的数放入大根堆,大一点的放入小根堆.
        q2.push(x);
        q1.push(y);
        if(q2.top()>q1.top())
        {
            int a=q2.top(),b=q1.top();
            q2.pop();
            q2.push(b);
            q1.pop();
            q1.push(a);
        }
        //最后每次要保证输出q2的top,让操作更加简单.
       cout<<q2.top()<<endl;
    }
    return 0;
}

 

推荐阅读