洛谷 - P1801 - 黑匣子 - 对顶堆

news/2024/7/7 14:20:54

这道题是提高+省选-的难度,做出来的话对数据结构题目的理解会增加很多。

可以使用一种叫做对顶堆的东西,对顶堆是在线维护第n小的logn的算法。大概的思路是,假如我们要找的是第n小,我们就维护一个大小为n的(位于下方的)大顶堆,(位于上方的)小顶堆中每个元素都比大顶堆的大。在这道题中,n不变时每次有新的比他小的就把堆顶弹出到对顶(也就是小顶堆)的堆顶,每次n扩大的时候就从(上面的)小顶堆里取出堆顶放进大顶堆的堆顶……

但是看样子应该其他平衡树也是可以解决这个问题的。比如支持快速名次的splay?还有完全另一个维度复杂的主席树(区间第k大)。

 

这道题应该是对顶堆最简单了。但是明显是用别的数据结构更好,因为对顶堆的第n小只能慢慢变……这样真的不如splay……(当然啦!splay这么复杂,你怎么不用主席树呢?主席树还区间第k大呢?)

Pdalao说了一个,可以用BST来维护,每个节点维护左子树的名次,那么找k的时候就可以判断是进入左子树还是右子树了,陷入思考……其实还是要旋转来保持平衡树的特性……

 

真实的递归学习法,一个两个都不会。


动态维护第k小也可以交给各类平衡树去完成。 而且k还可以不断改。

对顶堆用来维护一种顶堆只会不断扩大的情形非常方便。和之前的动态求中位数一个道理。

这里我们根据题目命名为“黑匣子堆”:注意每次顶堆扩大时,假如底堆有元素则优先从底堆获取。

#include<bits/stdc++.h>
using namespace std;

struct Black_Box_Heap{
    //top_heap has the min element,bottom heap has the max element

    priority_queue<int,vector<int>,less<int> > top_heap;
    priority_queue<int,vector<int>,greater<int> > bottom_heap;

    int i;

    Black_Box_Heap(){i=0;}

    void add(int value){
        if(top_heap.size()<=i){
            top_heap.push(value);
        }
        else{
            if(value<top_heap.top()){
                bottom_heap.push(top_heap.top());
                top_heap.pop();
                top_heap.push(value);
            }
            else{
                bottom_heap.push(value);
            }
        }
    }

    int get(){
        int t=top_heap.top();
        i++;
        while(top_heap.size()<=i&&!bottom_heap.empty()){
            top_heap.push(bottom_heap.top());
            bottom_heap.pop();
        }
        return t;
    }
}bbh;

int a[200005];

int main(){
    int m,n;
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++){
        scanf("%d",&a[i]);
    }

    int j=1;
    for(int i=1;i<=n;i++){
        int u;
        scanf("%d",&u);
        while(u>=j){
            bbh.add(a[j]);
            j++;
        }

        printf("%d\n",bbh.get());
    }
}

 

转载于:https://www.cnblogs.com/Yinku/p/10319627.html


http://www.niftyadmin.cn/n/4556315.html

相关文章

周学习总结

花费时间&#xff1a;3.53.52.53.5215小时 代码行数&#xff1a;400左右 学习内容&#xff1a;jsp基本语法&#xff08;学自jsp基础教程&#xff09;&#xff0c;java web&#xff08;bilibili视频&#xff09;。转载于:https://www.cnblogs.com/lianghang/p/10502654.html

PostProcessing后期处理插件

PostProcessing后期处理插件 先占个位置posted on 2019-03-10 13:08 青先生 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/Mr-QingZi/p/10504986.html

c#线程2

多线程中很有可能存在争夺一个变量资源而产生死锁或者不被期望的结果。 测试类; class TestClass{private int num 100;private object objLock new object();public void MissYou(){while (true){lock (objLock){SomeTest();}}}public void SomeTest(){num;if (num 100){Co…

C#操作文本文件

123 12 1 StringSplitOptions.None);//分成数组你要书一下 用StreamWriter的WriteLine()方法写入 怎么提交了呢- -string[] spliter { "/r/n" };//换行符分割string[] configs configstr.Split(spliter 没答完呢 把这个字符串用Split()方法分割 答案补充 郁闷 把文…

C语言中函数调用与返回值的关系是什么

而函数是负责要做什么 3); //调用函数 3我们称为形式参数 int sum(int arg1 并传递参数3和4过去 函数将计算机过程封装 也就可以说没有返回值 ||| 函数调用和返回值的关系其实和赋值运算的道理是一样的只是 他就返回空 如果没有return语句 如果函数里有return后便那个值就是返回…

【C语言问题】<一个三位数 它的各个数字位的立方和等于它本身 比如:153=1*1*1+5*5*5+3*3*3>用C语言怎么编写

大概意思就是这个 ge; //百 n);} ||| for(i1;i<10;i) for(j1;j<10;j) for(k1;k<10;k) { if(i*i*ij*j*jk*k*ki*100j*10k) printf(数字为&#xff1a;i*100j*10k); }很久没用C了 做repeat次下列运算&#xff1a;输入2 个正整数m和n(1<m &n);for(im;i<n;i){ su…

c大小的程序。 b 怎么用turboC编辑一个比较a

c:temp; printf("%d/n" &b &a temp; printf("请输入a b c:"); scanf("%d %d %d" c b #include <stdio.h>void main(){ int a 就空一格 直接putchar(C); ||| a b c d e f g 嘛 a:b; c c>temp 都看不懂 &c); //第输入完一个…