POJ 1442 Black box(单调队列求第k小数)

来源:互联网 发布:抢购软件 编辑:程序博客网 时间:2024/04/30 23:53

思路来自:http://chjzhacm.blog.163.com/blog/static/174901413201122771715851/


题目意思是有两种命令ADDx)和GET(x)

ADDx 在已有序列中加入x元素

GETx 在执行xADD命令后得到已有序列中第i小的元素  i初始为0每次执行GET命令前i要先加1

ADDGET最多都是30000

 

在这里,我们可以维护两个堆,一个为大根堆,一个为小根堆

现在,我们的目标是让前i-1小的数放在大根堆,那么此时小根堆的堆顶便是我们所要求的第i小的数

问题是,我们要如何维护两个堆,让整个数据序列在插入过程中,保持前i-1小的数放在大根堆呢?

用如下做法:

       1、每执行完一次ADD操作,取小根堆的堆顶放到大根堆,删除小根堆堆顶,取大根堆顶放到小根堆,删除大根堆堆顶。执行完一次这样的操作后,大根堆的元素个数保持不变还是i-1个,同时大根堆里面的元素是整个序列中前i-1小的部分,小根堆的堆顶大于或等于大根堆里的任意一个元素

        2、执行GET操作的时候,小根堆的堆顶便是第i小的数 ,为了方便,下面代码中直接把小根堆的堆顶放到大根堆中,以准备下一次的操作




#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<vector>#define bug(a) cout<<a<<"---->\n";using namespace std;int A[30010],u[30010];int main(){    priority_queue<int,vector<int>,greater<int> > q1;    priority_queue<int> q2;    int n,m;    scanf("%d%d",&n,&m);    for(int i=0;i<n;i++)        scanf("%d",A+i);    for(int i=0;i<m;i++)        scanf("%d",u+i);    int t=0;    for(int i=0;i<m;i++)    {        while(t<u[i])        {            q1.push(A[t]);            if(!q2.empty()&&q1.top()<q2.top())            {                int temp=q1.top();                q1.pop();                q1.push(q2.top());                q2.pop();                q2.push(temp);            }            t++;        }        printf("%d\n",q1.top());        q2.push(q1.top());        q1.pop();    }    return 0;}


0 0
原创粉丝点击