对顶堆是用两个优先队列组成的数据结构,一个大根堆,一个小根堆。
queue实质上是个堆
默认queue是大根堆,指的是最大的元素会被排到堆顶;小根堆则是小元素在堆顶,可以用<int,vector<int>,greater<int> >来写
模板题P1168 中位数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <iostream>
#include <queue>
using namespace std;
int main()
{
int n;cin>>n;
priority_queue<int> q1;
priority_queue<int,vector<int>,greater<int>> q2;
//大根堆小于等于ak 小根堆的数字大于ak
//比如说ak等于6查询第k大元素,在小根堆的堆顶12345和9876
//6就是要找的数字
for(int i=1;i<=n;i++)
{
int x;scanf("%d",&x);
if(q2.empty()||x>=q2.top())
{
q2.push(x);
}else
{
q1.push(x);
}
int k=(i)/2+1;
while(q2.size()>k) q1.push(q2.top()),q2.pop();
while(q2.size()<k) q2.push(q1.top()),q1.pop();
if(i%2==1)
printf("%d\n",q2.top());
}
return 0;
}
放数字的时候,第一个数放q2里面,放入一个数,如果这个数大于q2顶,就放入q2.否则放入q1.
通过维护q1的大小为k。q1的堆顶就是寻找的第k个数。
通过这种方式可以动态的寻找第k大的数,而且复杂度很低。
动态寻找第k小的数,其实就是寻找第n-k+1大的数,对顶堆模板改一下就可.
#include <iostream>
#include <queue>
using namespace std;
int a[31000];
int ask[31000];
int main()
{
int n,m;cin>>n>>m;
priority_queue<int> q1;
priority_queue<int,vector<int>,greater<int>> q2;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=m;i++)
{
cin>>ask[i];
}
int p=1;
for(int i=1;i<=n;i++)
{
int x;x=a[i];
if(q2.empty()||x>=q2.top())
{
q2.push(x);
}else
{
q1.push(x);
}
int k=0;
while(ask[p]==i&&p<=m)
{
k=i-p+1;
p++;
while(q2.size()>k) q1.push(q2.top()),q2.pop();
while(q2.size()<k) q2.push(q1.top()),q1.pop();
printf("%d\n",q2.top());
}
if(p>m) break;
}
return 0;
}