博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
对顶堆学习笔记
阅读量:5757 次
发布时间:2019-06-18

本文共 2708 字,大约阅读时间需要 9 分钟。

\(\\\)

对顶堆


处理动态中位数等问题,灵活运用了堆的性质,本质是维护两个堆。

大根堆\(Q_1\):维护集合中较小值的部分的最大值。

小根堆\(Q_2\):维护集合中较大值的部分的最小值。

注意到两个堆中的元素各自是单调的,两个堆间也是单调的。也就是说,\(Q_1\)中的任何一个元素都不大于\(Q_2\)中的任何一个元素。

那么假设高度为权值,两个堆可以形象化的表示成:

5ba1ab4d4f565.png

如果两个堆的大小相差不超过\(1\),较大的那个堆的堆顶必定是中位数(偶数个数时中位数是排序后中间的两个之一)

\(UPD:\) 图中的 \(Q1\)\(Q2\) 标反了,权值是越高越大。

\(\\\)

具体操作


  • 插入

    先找到当前正确的集合插入,比较与堆顶的大小关系,大于小根堆的堆顶就插入大根堆,反之小根堆。

    调整两个堆的大小关系,因为两个堆不管是总体上还是各自内都是满足单调性的,所以每次取更大的堆的堆顶,插入另一个堆,直到两个堆的大小相差不超过\(1\)

    代码使用的是\(STL\)\(priority\_queue\),默认大根堆所以\(Q_1\)需要通过相反数实现。

    (!q2.size()||x>q2.top())?q1.push(-x):q2.push(x);while(q1.size()>q2.size()+1){q2.push(-q1.top());q1.pop();}while(q2.size()>q1.size()+1){q1.push(-q2.top());q2.pop();}
  • 查询

    直接输出比较大的堆的堆顶就好,注意\(Q_1\)的输出。

    if(i&1) printf("%d\n",(q1.size()>q2.size())?-q1.top():q2.top());
  • 扩展

    动态\(K\)大值:维护思想不变,只需要让\(Q_1\)的大小为\(K\)即可。

    带删除\(K\)大值\(/\)中位数:手写可删堆\(/\)打标记懒惰删除法

  • 模板

    以 为例,只有插入操作,每插入到奇数个就输出当前中位数,多组数据。

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #define N 100010#define R register#define gc getcharusing namespace std;inline int rd(){ int x=0; bool f=0; char c=gc(); while(!isdigit(c)){if(c=='-')f=1;c=gc();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();} return f?-x:x;}int n,x,cnt;priority_queue
    q1,q2,tmp;inline void work(){ cnt=0; x=rd(); n=rd(); q1=tmp; q2=tmp; printf("%d %d\n",x,(n+1)/2); for(R int i=1,x;i<=n;++i){ x=rd(); (!q2.size()||x>q2.top())?q1.push(-x):q2.push(x); while(q1.size()>q2.size()+1){q2.push(-q1.top());q1.pop();} while(q2.size()>q1.size()+1){q1.push(-q2.top());q2.pop();} if(i&1){ printf("%d ",(q1.size()>q2.size())?-q1.top():q2.top()); if((++cnt)==10&&i!=n) cnt=0,puts(""); } } puts("");}int main(){ int t=rd(); while(t--) work(); return 0;}

\(\\\)


对一个集合一共有\(N\)次操作,计数器\(cnt\)初始为\(0​\)

  • \(ADD\ x\):把\(x\)放进该集合。
  • \(GET\):将\(cnt\)\(1\),输出集合种中第\(cnt\)小的数。

  • \(N\in [1,2\times 10^5]\)

\(\\\)

动态\(K\)小值,注意题目限制的\(Q_2\)大小是变化的,每次询问后记得调整好。

\(\\\)

#include
#include
#include
#include
#include
#include
#include
#include
#define N 200010#define R register#define gc getcharusing namespace std;inline int rd(){ int x=0; bool f=0; char c=gc(); while(!isdigit(c)){if(c=='-')f=1;c=gc();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();} return f?-x:x;}int n,m,cnt,x,a[N];priority_queue
q1,q2;int main(){ n=rd(); m=rd(); for(R int i=1;i<=n;++i) a[i]=rd(); x=rd(); for(R int i=1;i<=n;++i){ (!q2.size()||a[i]>q2.top())? q1.push(-a[i]):q2.push(a[i]); while(q2.size()>cnt) q1.push(-q2.top()),q2.pop(); while(q2.size()

转载于:https://www.cnblogs.com/SGCollin/p/9673252.html

你可能感兴趣的文章
Pinpoint跨节点统计失败
查看>>
【Canal源码分析】Canal Server的启动和停止过程
查看>>
机房带宽暴涨问题分析及解决方法
查看>>
iOS 绕过相册权限漏洞
查看>>
我的友情链接
查看>>
XP 安装ORACLE
查看>>
八、 vSphere 6.7 U1(八):分布式交换机配置(vMotion迁移网段)
查看>>
[转载] 中华典故故事(孙刚)——19 万岁
查看>>
修改hosts文件里面的主机名,oralce asm无法启动
查看>>
Maven学习总结(十)——使用Maven编译项目gbk的不可映射问题
查看>>
php5编译安装常见错误和解决办法集锦
查看>>
Linux远程访问及控制
查看>>
MongoDB实战系列之五:mongodb的分片配置
查看>>
Unable to determine local host from URL REPOSITORY_URL=http://
查看>>
java基础(1)
查看>>
ORACLE配置,修改tnsnames.ora文件实例
查看>>
Workstation服务无法启动导致无法访问文件服务器
查看>>
.Net组件程序设计之远程调用(二)
查看>>
ant中文教程
查看>>
Linux常用命令(一)
查看>>