点名
【题目描述】
在J班的体育课上,同学们常常会迟到几分钟,但体育老师的点名却一直很准时。老师只关心同学的身高,他会依次询问当前最矮的身高,次矮的身高,第三矮的身高,等等。在询问的过程中,会不时地有人插进队伍里。你需要回答老师每次的询问。
【输入格式】
第一行两个整数n m,表示先后有n个人进队,老师询问了m次
第二行n个整数,第i个数Ai表示第i个进入队伍的同学的身高为Ai
第三行m个整数,第j个数Bj表示老师在第Bj个同学进入队伍后有一次询问
【输出格式】
m行,每行一个整数,依次表示老师每次询问的答案。数据保证合法
【样例输入】
7 4
97281418
1 2 6 6
【样例输出】
9
9
7
8
【样例解释】
(9){No.1 = 9}; (9 7){No.2 = 9}; (9 7 2 8 14 1){No.3 = 7; No.4 = 8}
【数据范围】
40%的数据保证n≤1000
100%的数据保证1≤m≤n≤30000;0≤Ai<2^32
大根堆与小根堆的巧妙结合
一个小根堆q1,一个大根堆q2
q2维护当前最小的k个值
所以每次的答案就是q2的堆顶
对于每次询问,
枚举上一次入队到这一次入队的人
向q2中加入这个人的高度,q1中加入q2的堆顶,删除q2堆顶
即加入新的,删除最大的,保持q2中始终是当前最小的k个
因为这个k是上一次询问的k
所以最后把q1的堆顶加入q2,删除q1堆顶
所以q1是小根堆
坑:数据 2^32 是long long
#include<queue> #include<cstdio> #define N 30001 using namespace std; long long a[N]; int b[N]; priority_queue<long long,vector<long long>,greater<int> >q1; priority_queue<long long>q2; void read(long long &x) { x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } } int main() { freopen("rollcall.in","r",stdin); freopen("rollcall.out","w",stdout); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) read(a[i]); for(int i=1;i<=m;i++) scanf("%d",&b[i]); for(int i=1;i<=m;i++) { for(int j=b[i-1]+1;j<=b[i];j++) { q2.push(a[j]); q1.push(q2.top()); q2.pop(); } q2.push(q1.top()); q1.pop(); printf("%I64d\n",q2.top()); } }