题目
题目描述
有一个长度为n的数组,值为 a[i], 牛牛想找到数组中第 k 小的数。比如 1 2 2 3 4 6 中,第 3 小的数就是2.
牛牛觉得这个游戏太简单了,想加一点难度,现在牛牛有 m 个操作,每个操作有两种类型。
1 x 1 代表操作一,给数组中加一个元素 x 。(0 ≤ x ≤ 1e9)
2 2 代表操作二,查询第 k 小的数。如果没有 k 个数就输出−1
输入描述:
第一行有三个整数,n m k,(1≤n,m,k≤2e5)
第二行包含 n 个整数 a[i] ( 0 ≤ a[i] ≤ 1e9)
接下来m行,每行代表一个操作。具体见题目描述
输出描述:
每次查询输出一个第 k 小的数。
示例1
输入
5 4 3 1 2 3 4 5 2 1 1 1 3 2
输出
3 2
思路
这道题就一道优先队列题,首先把所有数存进优先队列(greater)s1里面,然后取前k个数放到优先队列(less)s2里面,然后每次添加数的时候把新输入的数x跟s2.top()对比一下。x小的话就让x入队、s2队首出队,反之就不用管。(还要另外考虑一下n<k的情况)
ACcode
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
priority_queue<ll,vector<ll>,greater<ll> > s1;//大根堆
priority_queue<ll,vector<ll>,less<ll> > s2;//小根堆
ll n,m,k;cin>>n>>m>>k;
for(ll i=1;i<=n;i++) {ll x;cin>>x;s1.push(x);}
ll f=0;
while(f<k&&(!s1.empty()))//把前k小的数放到s2里面
{
s2.push(s1.top());
s1.pop();
f++;
}
while(m--)
{
ll q;cin>>q;
if(q==1)
{
ll x;cin>>x;
if(s2.size()<k) //如果没有k个数
{
s2.push(x);
}
else if(x<s2.top()) //有k个数的话判断一下新输入的数是否比前k个数小
{
s2.push(x);//是就加入s2
s2.pop();//第k+1小的数出列
}
}
else
{
if(s2.size()==k) cout<<s2.top()<<endl;
else cout<<-1<<endl;
}
}
return 0;
}