- 这个题大意是有一个数据结构支持两种操作A与Get操作,其中A x表示插入x. Get i表示返回结构中的第i小的数.给你A和Get操作的顺序和参数,现在要你对每个Get输出值.
- 取前u(i)个数排序~
- 然后取第i个数~(i=1,2,3……)
- 后来发现可以用大顶堆和小顶堆做~
- 每次将u(i)个数存入小顶堆中~
- 取小顶堆堆顶元素存入大顶堆中~
- 删除堆顶元素~
- 将大顶堆堆顶元素存入小顶堆中删除堆定元素~
- 这样大顶堆中的元素个数不变~
- 总是最小的前i个~
题解:每次取第k小元素,k不断更新。使用两个堆,来完成。 小顶堆负责选出最小的元素,大顶堆负责选出k个元素中最大的元素,即第k小元素
大顶堆的堆顶元素始终小于小顶堆的堆顶元素,这样的话大顶堆中的所有元素都小于小顶堆中的元素,如果大顶堆中有k-1个元素,那么小顶堆的堆顶元素就是要找的 第k小 元素了
Sample Input
7 4 ( n,m,分别是a数组,u数组的元素个数)
3 1 -4 2 8 -1000 2 (a数组)
1 2 6 6 (数u[i]w为几就加到a几,然后输出第i 小的:输出数组a前1个第1小的,前两个第2小的,前6个第3小的,前6个第4小的)
Sample Output
3
3
1
2
- 大根堆分别有1、2、3、4个元素 3 ,3 1,3 1 -4 2 8 -1000,3 1 -4 2 8 -1000。。。。3,3 1,1 -4 -1000,1 -4 2 -1000。。。。_,1, -4 -1000,1 -4 -1000
- 小顶堆元素为 3,3,3 1 2 8,3 2 8 即负责选出最小元素
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
const int maxint=30010;
int num[maxint];
int query[maxint];
priority_queue<int ,vector <int> ,less<int> >p2;//大根堆
priority_queue<int ,vector <int> ,greater<int> >p1;//小根堆
int main()
{
int m,n,i,j,k;
int temp;
while(scanf("%d%d",&m,&n)!=EOF)
{
for(i=0;i<m;i++)
scanf("%d",&num[i]);
for(i=0;i<n;i++)
scanf("%d",&query[i]);
//输入结束之后,就是从头到尾维护一个大根堆和小根堆
//大根堆中始终存放在查询之前的元素
j=0;
for(i=0;i<m;i++)
{
p2.push(num[i]);//把第i个元素放入大根堆
p1.push(p2.top());//把大根堆的最大元素放入小根堆
p2.pop();
if(query[j]==i+1)//当前询问
{
while(query[j]==i+1)
{
temp=p1.top();//小根堆的最小元素就是第i+1小的元素,因为大根堆中的i个元素
p1.pop();//都小于temp
p2.push(temp);
printf("%d\n",temp);
j++;
}
}
}
}
return 0;
}
题外话丨分治法 直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。