洛谷 P1801

题目链接: P1801 黑匣子

题目大意

题目描述的已经够清楚了, 我就不说了自己读吧

solution

哇, 查询区间第 \(k\) 大诶, 平衡树~

写平衡树的话, 觉得有点大材小用了, 那我们用什么做呢?

堆+贪心!

那我们怎么贪呢? 我们的贪心思路是什么呢?

我们维护两个堆, 一个大根堆维护小于第 \(k\) 小的值的元素, 一个小根堆维护大于等于第 \(k\) 小的值的元素

我们怎么判断是第 \(k\) 小呢, 大根堆的 \(size+1\) 就是第 \(k\) 小每次放元素的时候判断一下就可以了

但是会不会有细节问题呢? 那啃腚是有的自己验证吧

code:

/**
*    Author: Alieme
*    Data: 2020.8.26
*    Problem: Luogu P1801
*    Time: O(nlogn)
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>

#define ll long long
#define rr register

#define inf 1e9
#define MAXN 500010

using namespace std;

inline int read() {
	int s = 0, f = 0;
	char ch = getchar();
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
	return f ? -s : s;
}

void print(int x) {
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) print(x / 10);
	putchar(x % 10 + 48);
}

priority_queue<int> q;

priority_queue<int, vector<int>, greater<int> >p;

int n, m, last;

int a[MAXN];

signed main() {
	n = read();
	m = read();
	for (rr int i = 1; i <= n; i++) a[i] = read();
	for (rr int i = 1; i <= m; i++) {
		int u = read();
		for (rr int j = last + 1; j <= u; j++) {
			q.push(a[j]);
			if (q.size() == i) p.push(q.top()), q.pop();
		}
		cout << p.top() << "\n";
		q.push(p.top());
		p.pop();
		last = u;
	}
}
posted @ 2020-08-26 08:22  Aliemo  阅读(96)  评论(2编辑  收藏  举报