POJ 1442

//7977992    vrs    1442    Accepted    516K    125MS    C    1930B    2010-12-07 13:26:53
//1142 黑盒数字 优先队列(大根堆+小根堆)
//这题看了别人的解题报告才弄出来的,感觉这里两个堆操作很巧妙
//维护两个优先队列,大根堆,小根堆,大根堆保存当前最小的i-1个数,并把i到u[p]个数放到小跟堆里,那么
//小根堆的最小值就是当前状态的第i小元素
//注意到一点,c不支持函数的按引用调用 &
#include<stdio.h>
#define  bool int
#define MAXNUM 30005

 

long minqu[MAXNUM];
long maxqu[MAXNUM];
int n1,n2;

//不支持按引用调用,所以用指针实现
void swap(long *a,long *b)
{
    long temp=*a;  *a=*b;  *b=temp;
}

void InsertMin(long data)
{
    long father,son;
    n1++;
    minqu[n1]=data;
    son=n1;
    while(son>1)
    {
        father=son/2;
        if(minqu[father]>minqu[son])
            swap(&minqu[father],&minqu[son]);
        else
            break;
        son=father;
    }
}

void InsertMax(long data)
{
    long father,son;
    n2++;
    maxqu[n2]=data;
    son=n2;
    while(son>1)
    {
        father=son/2;
        if(maxqu[father]<maxqu[son])
            swap(&maxqu[father],&maxqu[son]);
        else
            break;
        son=father;
    }
}

bool IsEmptyMin()
{
    if(n1==0)
        return 1;
    else
        return 0;
}

bool IsEmptyMax()
{
    if(n2==0)
        return 1;
    else
        return 0;
}

int TopMin()
{
    return 1;
}

int TopMax()
{
    return 1;
}

void PopMin()
{
    int father,son;
    swap(&minqu[1],&minqu[n1]);
    n1--;
    father=1;
    while(father<=n1/2)
    {
        son=father*2;
        if(son+1<=n1 && minqu[son]>minqu[son+1])
            son++;
        if(minqu[father]>minqu[son])
            swap(&minqu[father],&minqu[son]);
        else
            break;
        father=son;
    }
}

void PopMax()
{
    int father,son;
    swap(&maxqu[1],&maxqu[n2]);
    n2--;
    father=1;
    while(father<=n2/2)
    {
        son=father*2;
        if(son+1<=n2 && maxqu[son]<maxqu[son+1])
            son++;
        if(maxqu[father]<maxqu[son])
            swap(&maxqu[father],&maxqu[son]);
        else
            break;
        father=son;
    }
}

int main()
{
    int M,N;
    int i,j,k;
    long a[30005];
    long u[30005];
    n1=n2=0;
    scanf("%d%d",&M,&N);
    for(i=1;i<=M;i++)
        scanf("%ld",&a[i]);
    for(i=1;i<=N;i++)
        scanf("%ld",&u[i]);

    i=1;u[0]=0;
    for(j=1;j<=N;j++)
    {
        while(i<=u[j])
            InsertMax(a[i++]);   
        for(k=u[j]-u[j-1];k>0;k--)
        {
            InsertMin(  maxqu[TopMax()]  );
            PopMax();
        }
        printf("%ld\n", minqu[TopMin()] );
        // 这里把TopMin()重新压进Max堆里很重要,这样就保证前i小个数一定留在Max堆里
        InsertMax( minqu[TopMin()] );
        PopMin();
    }
    return 0;
}

你可能感兴趣的:(poj)