• 「数据结构」对顶堆


    走进堆

    堆分为大根堆和小根堆,大根堆堆顶元素最大,越往下元素越小,小根堆相反,堆顶元素最小,越往下元素越大

    1.定义

    手写堆是什么,表示从来没用过,要写堆当然要用我STL的优先队列啦

    priority_queue<int> q;//默认的优先队列是大根堆
    
    priority_queue<int,vector<int>,less<int> >;//大根堆的展开,注意:less<int>后必须加个空格,否则会CE
    
    priority_queue<int,vector<int>,greater<int> >;//小根堆
    

    2.函数

    当然是跟队列一样,插入的话就不用管了,优先队列自动给排

          q.push(a);//插入a这个元素
          q.top();//堆顶
          q.pop();//弹出堆顶元素
    

    例题:洛谷P3378 堆

    对顶堆

    对顶堆,故明此意,是这样滴:


    (摘自洛谷博主婷菡)
    其实就是用一个大根堆和一个小根堆,大根堆在上,小跟堆在下,从上到下依次增大


    (摘自Sugewud_的CSDN博客)

    对顶堆的性质

    1.大根堆在上,小跟堆在下,从上到下依次增大

    2.序列的中位数是大小根堆中较大根堆的堆顶

    代码:

    详见例题:洛谷P1168 中位数

    写法1:假的对顶堆(中位数不在两个堆中)(极不推荐)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int maxn=1e6+5,INF=0x3f3f3f3f;
    int n,a[maxn],mid;
    inline int read(){
    	int s=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    	return s*w;	
    }
    priority_queue<int,vector<int>,less<int> > q1;//大根堆
    priority_queue<int,vector<int>,greater<int> >q2;//小根堆
    int main(){
    	freopen("a.in","r",stdin);
    	int n=read();
    	a[1]=read();
    	mid=a[1];
    	cout<<a[1]<<endl;
    	for(int i=2;i<=n;i++){
    		a[i]=read();
    		if(a[i]>mid)q2.push(a[i]);//大进大的小根堆
    		else q1.push(a[i]);//小进小的大根堆
    		if(i%2==1){
    			while(q1.size()!=q2.size()){//维护堆,因为中位数不在堆中,所以while条件为q1.size()!=q2.size()
    				if(q1.size()>q2.size()){
    					q2.push(mid);
    					mid=q1.top();
    					q1.pop();
    				}else{
    					q1.push(mid);
    					mid=q2.top();
    					q2.pop();
    				}
    			}
    			cout<<mid<<endl;
    		}
    	}
    
    }
    

    写法2:真的对顶堆(极度推荐)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int maxn=1e6+5,INF=0x3f3f3f3f;
    int n,a[maxn],mid;
    inline int read(){
    	int s=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    	return s*w;	
    }
    priority_queue<int> q1;
    priority_queue<int,vector<int>,greater<int> > q2;
    int main(){
    	n=read();
    	a[1]=read();
    	cout<<a[1]<<endl;
    	q1.push(a[1]);
    	for(int i=2;i<=n;i++){
    		int x=read();
    		if(x>q1.top())q2.push(x);//大进大的小根堆
    		else q1.push(x);//小进小的大根堆
    		while(abs(int(q1.size()-q2.size()))>1){//维护堆,!!!注意:必须加int,因为size()的返回类型是unsigned,没有负数
    			if(q1.size()>q2.size())q2.push(q1.top()),q1.pop();
    			else q1.push(q2.top()),q2.pop();
    		}
    		if(i%2==1){
    			if(q1.size()>q2.size())cout<<q1.top()<<endl;
    			else cout<<q2.top()<<endl;
    		}
    	}
    }
    

    例题: P1801 黑匣子

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int maxn=1e6+5,INF=0x3f3f3f3f;
    int n,a[maxn],mid,l=1,r,m;
    inline int read(){
    	int s=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    	return s*w;	
    }
    priority_queue<int,vector<int>,less<int> > q1;
    priority_queue<int,vector<int>,greater<int> >q2;
    int main(){
    	//freopen("a.in","r",stdin);
    	n=read();m=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    
    	for(int i=1;i<=m;i++){
    		r=read();
    		for(int j=l;j<=r;j++){
    			q1.push(a[j]);
    			
    		}
    		while(q1.size()>=i)q2.push(q1.top()),q1.pop();
    		l=r+1;
    		cout<<q2.top()<<endl;
    		q1.push(q2.top());q2.pop();
    	}
    	
    
    }
    

    OVER~

  • 相关阅读:
    linux 程序后台运行
    小型网站架构技术点(简要)
    rsync安装与配置使用 数据同步方案(centos6.5)
    nfs的原理 安装配置方法 centos6.5
    centos 6.5 升级到 python2.7
    ntpdate 设置时区(注意本地时区要设置正确)
    关于umask的计算方式(简单任性)
    No space left on device(总结)
    lsof 查看打开了一个文件的有哪些进程 统计那个进程打开的文件最多
    作用域是什么?
  • 原文地址:https://www.cnblogs.com/614685877--aakennes/p/13199313.html
Copyright © 2020-2023  润新知