Luogu1801 黑匣子 堆

传送门

题意:给出两种命令:

ADD(x):把 x 元素放进 Black Box;

GET:i 加 1,然后输出 Black Box 中第 i 小的数。

输出每次GET操作的结果。

题解:
注意到每次求的第k小中,k从1开始递增。则维护一个大根堆和一个小根堆,大根堆里记录前K小的数字,小根堆里记录其他的数字。
这样构造有一个性质:
1.大根堆里最大的数即为当前数组中的第K小。
在遇到GET操作之前,对于每个待加入的数字,判断其是否为前K小,若是,则加入到大根堆中,并把大根堆中最大的数放到小根堆中;否则直接加入小根堆。
GET操作:取出小根堆里面最小的数即为答案,再将这个数取出加入到大根堆中,满足上面的性质。

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 200005, MAXM = 200005;

int a[MAXN];

inline int read(){
	int k = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){k = k * 10 + ch - '0'; ch = getchar();}
	return k * f;
}

priority_queue <int> q1, q2;
//q1为小根堆,q2为大根堆 

int main(){
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	int m = read(), n = read();
	for(int i = 1; i <= m; i++){
		a[i] = read();
	}
	
//	for(int i = 1; i <= m; i++){
//		printf("%d ", -q1.top());
//		q1.pop();
//	}
	
	int now = 0, kth = 0, cur = 0;
	for(int i = 1; i <= n; i++){
		int k = read();
		while(now < k){
			now++;
			if(!q2.empty()){
				int x = q2.top();
				if(x > a[now]){
					q2.pop();
					q1.push(-x);
					q2.push(a[now]);
				}
				else{
					q1.push(-a[now]);
				}
			}
			else{
				q1.push(-a[now]);
			}
			
		}
		kth++;
		int q1min = -q1.top(); q1.pop();
		q2.push(q1min);
		printf("%d
", q1min);
	}
	
	return 0;
}
原文地址:https://www.cnblogs.com/asdf1229/p/13886127.html