JZOJ P2152 终极数

目录:


题目:

传送门


分析:

对于20%的数据:

直接暴力


对于40%的数据:

显然的,对于一个序列的终极数,肯定就是这个序列的中位数,那么可以用快排,做到 O ( ݊ n 2 l o g 2 n )


对于100%的数据:

找中位数,可以用堆:
我们维护两个堆,一个大根堆,一个小根堆,当前每次加入一个数,必须保证
小根堆的个数大于等于大根堆的个数,亦即——第一次加入数的时候肯定是放
到最小堆。
其次,我们还需保证小根堆里的每个值必须大于等于大根堆当中的最大值。
并且,我们当前大根堆的个数如果已经小于小根堆的话,则要把下一个数加到
大根堆里,反之亦然。
而当我们加入一个数时,会有两种特殊情况:
设加入的数为 x ,如果欲加入到大根堆里时, x 大于小根堆的堆顶,则进行 t e m p 1 操作。
反之——如果欲加入到小根堆里时, x 小于大根堆的堆顶,则进行 t e m p 2 操作。
t e m p 1 x 放到小根堆中,并且把小根堆的堆顶放到大根堆当中,并维护两堆
性质。
t e m p 2 x 放到大根堆中,并且把大根堆的堆顶放到小根堆当中,并维护两堆
性质。
最后我们再对所有的终极数 x i 进行一次排序,找出最小的终极数 t 即可,可证至多有两个终极数。
时间复杂度 O ( n l o g 2 n )


代码:

#pragma GCC optimize(3)
//O3大法好,用了直接少200ms
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
int x[500005],y[500005],zj[1000001],n,xs=0,ys=0;
//x为小根堆,y为大根堆
void upx(int w)
{
    while(w>1&&x[w/2]>=x[w]) swap(x[w],x[w/2]),w/=2;
    return;
}
void upy(int w)
{
    while(w>1&&y[w/2]<=y[w]) swap(y[w],y[w/2]),w/=2;
    return;
}
void downx(int w)
{
    int a;
    while(w*2<=xs&&x[w]>x[w*2]||w*2+1<=xs&&x[w]>x[w*2+1])
      {
        a=w*2;
        if(a+1<=xs&&x[a]>x[a+1]) a++;
        swap(x[w],x[a]);
        w=a;
      }
    return;
}
void downy(int w)
{
    int a;
    while(w*2<=ys&&y[w]<y[w*2]||w*2+1<=ys&&y[w]<y[w*2+1])
      {
        a=w*2;
        if(a+1<=ys&&y[a]<y[a+1]) a++;
        swap(y[w],y[a]);
        w=a;
      }
    return;
}
int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    int a;
    n=read();
    for(int i=1;i<=n;i++)
    {
        a=read();
        if(xs<=ys) 
        {
            if(a<y[1])
            {
                x[++xs]=y[1];
                upx(xs);
                downx(1);
                y[1]=a;
                downy(1);
            }
            else 
            {
                x[++xs]=a;
                upx(xs);
                downx(1);
            }
        }
        else
        {
            if(a>x[1])
            {
                y[++ys]=x[1];
                upy(ys);
                downy(1);
                x[1]=a;
                downx(1);
            }
            else
            {
                y[++ys]=a;
                upy(ys);
                downy(1);
            }
        }
        zj[i]=x[1];
    }
    sort(zj+1,zj+n+1);
    printf("%d",zj[n/2]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35786326/article/details/81670140