Ural1306-Sequence Median

有n个数,求这n个数排序后的中间数,如果n为奇数,中间数即为排序后中间那个元素,如果n为偶数就是中间两个元素的平均数。

由于内存只有1M,所以无法存下所有数值进行排序,因此,考虑将n/2+1个元素放入一个优先队列(堆)中,然后每次将剩下的元素逐个放进优先队列中并抛出堆中最大的元素。
这样以后如果n为奇数,队首元素即为中间数;如果是偶数,那么先记录队首元素,再抛出队首元素,原队首与当前队首元素之和除以2就是中间数。

但是如果维护一个优先队列还是会MLE,需要换用make_heap,push_heap和pop_heap函数。

void make_heap (RandomAccessIterator first, RandomAccessIterator last);
void make_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp );

将迭代器[first, last)范围内的元素按堆序排序,默认生成最大堆(大根堆)
注:The element with the highest value is always pointed by first. The order of the other elements depends on the particular implementation, but it is consistent throughout all heap-related functions of this header.
最大值一定在堆顶,剩余元素的顺序依赖于具体的实施。

void push_heap (RandomAccessIterator first, RandomAccessIterator last);
void push_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

调用push_heap时认为[fitst, last-1)区间内为一个有效堆,然后将last-1指向的元素放入堆中。

void pop_heap (RandomAccessIterator first, RandomAccessIterator last);
void pop_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

调用pop_heap时将堆顶的元素移到last-1的位置上,即移出原来的堆,再在[first, last-1)范围内重新建堆。

在我尝试使用vector依然MLE之后,选择了用数组代替,这样需要稍微改变一下,放入剩余元素时先比较一下待入堆元素是否小于堆顶元素,如果是就pop_heap并用新值覆盖原来的堆顶元素,然后push_heap。

#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

const int maxn = 250000;

int a[maxn/2+5];

int main(int argc, char const *argv[]) {
    int n;
    double ans;
    scanf("%d", &n);
    for (int i = 0; i < n / 2 + 1; i++) {
        scanf("%d", &a[i]);
    }
    make_heap(a, a + n / 2 + 1);

    for (int i = n / 2 + 1; i < n; i++) {
        int val;
        scanf("%d", &val);
        if (val < a[0]) {
            pop_heap(a, a + n / 2 + 1);
            a[n/2] = val;
            push_heap(a, a + n / 2 + 1);
        }
    }
    if (n & 1) {
        ans = a[0];
    } else {
        ans = a[0];
        pop_heap(a, a + n / 2 + 1);
        ans += a[0];
        ans /= 2;
    }
    printf("%.1f\n", ans);
    return 0;
}

这道题同时给了我一些思考,STL中的priority_queue事实上也调用了make_heap,那么是不是可以说,优先队列就是一些元素按某种堆序排列后组成的队列?

附STL priority_queue源码:

// TEMPLATE CLASS priority_queue
template < class _Ty,
         class _Container = vector<_Ty>,
         class _Pr = less<typename _Container::value_type> >
class priority_queue
{
    // priority queue implemented with a _Container
public:
    typedef _Container container_type;
    typedef typename _Container::value_type value_type;
    typedef typename _Container::size_type size_type;
    typedef typename _Container::reference reference;
    typedef typename _Container::const_reference const_reference;

    priority_queue()
        : c(), comp()
    {
        // construct with empty container, default comparator
    }

    explicit priority_queue(const _Pr &_Pred)
        : c(), comp(_Pred)
    {
        // construct with empty container, specified comparator
    }

    priority_queue(const _Pr &_Pred, const _Container &_Cont)
        : c(_Cont), comp(_Pred)
    {
        // construct by copying specified container, comparator
        make_heap(c.begin(), c.end(), comp);
    }

    template<class _Iter>
    priority_queue(_Iter _First, _Iter _Last)
        : c(_First, _Last), comp()
    {
        // construct by copying [_First, _Last), default comparator
        make_heap(c.begin(), c.end(), comp);
    }

    template<class _Iter>
    priority_queue(_Iter _First, _Iter _Last, const _Pr &_Pred)
        : c(_First, _Last), comp(_Pred)
    {
        // construct by copying [_First, _Last), specified comparator
        make_heap(c.begin(), c.end(), comp);
    }

    template<class _Iter>
    priority_queue(_Iter _First, _Iter _Last, const _Pr &_Pred,
                   const _Container &_Cont)
        : c(_Cont), comp(_Pred)
    {
        // construct by copying [_First, _Last), container, and comparator
        c.insert(c.end(), _First, _Last);
        make_heap(c.begin(), c.end(), comp);
    }

    bool empty() const
    {
        // test if queue is empty
        return (c.empty());
    }

    size_type size() const
    {
        // return length of queue
        return (c.size());
    }

    const_reference top() const
    {
        // return highest-priority element
        return (c.front());
    }

    reference top()
    {
        // return mutable highest-priority element (retained)
        return (c.front());
    }

    void push(const value_type &_Pred)
    {
        // insert value in priority order
        c.push_back(_Pred);
        push_heap(c.begin(), c.end(), comp);
    }

    void pop()
    {
        // erase highest-priority element
        pop_heap(c.begin(), c.end(), comp);
        c.pop_back();
    }

protected:
    _Container c;   // the underlying container
    _Pr comp;   // the comparator functor
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值