题目链接:http://poj.org/problem?id=1442
题意:就是两个操作,add是加入一个数,get是获取第i小的数,每次get的时候i都加1.输入的话,第一行a数组就是所有的需要逐次加进队列的数字,第二行u数组代表当队列中元素的个数为多少时执行一次get操作。
解析:自己做的话曾经想到用set,但是最后的话因为set无法查询第k小的数,只能查询确定值的数。所以用迭代器从begin()开始加的话,最后超时了。看了大牛的博客才发现原来可以用两个优先队列来维护。一个是大堆,从大到小,一个是小堆,从小到大。其中要使小堆的堆顶始终大于大堆的堆顶。这样的话小堆堆顶存储的始终就是第i小的了。
//算法:用两个优先队列的堆来维护,其中q1为从小到大排列,q2从大到小排列。每次保证q1堆顶的数字大于q2堆顶的数据,
//则q1堆顶的数据就是第i小的数据
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
#include<functional>
#define INF 31000
using namespace std;
int m,n,cnt,a[INF],u;
priority_queue<int,vector<int>,greater<int> > q1; //从大到小
priority_queue<int,vector<int>,less<int>> q2; //从小到大
int main()
{
while(scanf("%d%d",&m,&n) != EOF)
{
memset(a,0,sizeof(a));
for(int i = 1 ; i <= m ; i ++)
scanf("%d",&a[i]);
int cnt = 1;
for(int i = 1; i <= n ; i ++)
{
scanf("%d",&u);
for(;cnt <= u;cnt++)
{
q1.push(a[cnt]);
if(!q2.empty() && q1.top() < q2.top()) //保证每次q1堆顶都大于q2堆顶,否则交换q1,q2的堆顶来保证q1堆顶大于q2
{
int t = q1.top();
q1.pop();
q1.push(q2.top());
q2.pop();
q2.push(t);
}
}
printf("%d\n",q1.top());
q2.push(q1.top()); //这两行保证了每次都是第cnt(即i)小的数据都在q1的堆顶
q1.pop(); //cnt = 1时,q2零个元素,cnt = 2,q2一个元素
}
}
return 0;
}