K优先队列——对顶堆(两种优先队列的组合)
题目描述
你需要维护一个队列,支持以下两种操作:
1.加入一个非负整数x;
2.取出当前队列中第k大的数字。
保证进行第二种操作时,队列中至少有k个数字。
部分数据经过加密,你需要依次处理每个操作才能获得正确的下一个操作。
输入
第一行包括三个非负整数n,k,p,分别表示操作次数,参数k以及数据是否进行过加密。
接下来n行,每行先给出一个数opt,表示操作类型。若opt=1,接下来还会有一个非负整数x,若p=0,表示往队列中加入x,若p=1,表示往队列中加入x异或上前一次出队操作取出的数字后得到的结果,如果还未进行过出队操作,把前一次取出的数字看作0。若opt=2,表示要求取出并输出当前队列中第k大的数字。
输出
对于每一个出队操作,输出一个正整数表示答案。
样例输入
5 2 1
1 2
1 3
2
1 3
2
样例输出
2
1
提示
对于100%的数据,1 ≤ k ≤ n ≤ 2∗105 ,0 ≤ x ≤ 109。
之前在upc也做过关于对顶堆的题,在洛谷 还有这道题
对顶堆是由大根堆小根堆组成的一种数据结构,经常用来处理在线第 k 大(小),或者是动态中位数的问题
在这里插上一张图
图片来源:https://www.luogu.com.cn/user/119261
在这一道题目中适合上面放小根堆,下面放大根堆,小根堆里面的元素的顺序是从小到大排序的,大根堆里面的元素是从大到小排列的。小根堆的堆顶为小根堆中最小的元素,大根堆中的元素是大根堆中最大的元素。
利用这一特点,用上面的小根堆储存大的 k 个元素,其余的元素储存小的部分元素,这样一来,这两个堆也有单调性,即小根堆的堆顶(小根堆中最小的元素)大于大根堆的堆顶(大根堆中最大的元素),满足从上到下递减的关系,所以,每次小根堆的堆顶就是第 K 大的元素。
目标就是动态维护小根堆中尽量满足 K 个元素,不足时如果大根堆中还有元素,就将大根堆中的元素放入小根堆(运行错误在这里),意思就是说,如果大根堆中没有元素就没有办法pop()
code:
#include <bits/stdc++.h>
using namespace std;
#define wuyt main
typedef long long ll;
#define HEAP(...) priority_queue<__VA_ARGS__ >
#define heap(...) priority_queue<__VA_ARGS__,vector<__VA_ARGS__ >,greater<__VA_ARGS__ > >
template<class T> inline T min(T &x,const T &y){return x>y?y:x;}
template<class T> inline T max(T &x,const T &y){return x<y?y:x;}
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();
if(c == '-')Nig = -1,c = getchar();
while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();
return Nig*x;}
#define read read()
const ll inf = 1e15;
const ll INF = 0x3f3f3f3f;
const int maxn = 3e5 + 7;
const int mod = 998244353;
#define pi 3.14159265358979323846
ll res,ans;
ll n,k,p;
priority_queue <ll ,vector<ll> ,greater<ll> > xiaogen;
priority_queue <ll ,vector<ll> ,less<ll> > dagen;
void in_it(ll x){
if(xiaogen.size()<k) xiaogen.push(x);
else{
if(xiaogen.size()&&xiaogen.top()<x){
dagen.push(xiaogen.top());
xiaogen.pop();
xiaogen.push(x);
}
else dagen.push(x);
}
}
int main()
{
n=read,k=read,p=read;
ll temp=0;
while(n--){
ll opt=read;
if(opt==1){
ll x=read;
if(p==0) in_it(x);
else in_it(x^temp);
}
else{
temp = xiaogen.top();
printf("%lld\n",temp);
xiaogen.pop();
if(dagen.size()){
xiaogen.push(dagen.top());
dagen.pop();
}
}
}
return 0;
}
/**
5 2 1
1 2
1 3
2
1 3
2
**/