点名

【题目描述】

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
",q2.top());
    }
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6995106.html