题解 P3871 【[TJOI2010]中位数】

orz各位大佬,题解太强了,主席树,堆,线段树,splay,还有暴力,太巨了。所以我用的是fhq treap(好像更高级)。算了。

反正都是平衡树,这道题就是动态求中位数,不会做的同学可以先做弱化版P1168

至于不会fhq treap的同学可以先点这里或上 Patrickpwq大佬的博客

fhq treap做这道题涉及到insert(插入)与find(求第k小的数),至于k,就随add增大就好了,所以说fhq treap太好用了。

insert的原理就不说了,至于find的原理我就简单讲一下,fhq treap是用treap来存,treap就是堆与树的合并,所以我们叫它二叉搜索树,所以它具有堆的性质,所以就搜右子树大小。(详细可以戳上面)

嗯,上代码。

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 200010
using namespace std;
int n,val[maxn],rnd[maxn],son[maxn][3],size[maxn],sum_p,m;
//val存权值,rnd存rand出的值,son存左右儿子,size存大小。
inline void read(int &x)
{
    x=0;int f=1; 
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9')
    {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
inline int newnode(int x)
{
    ++sum_p;size[sum_p]=1;
    val[sum_p]=x;rnd[sum_p]=rand();
    return sum_p; 
}
inline void update(int x)
{
    size[x]=size[son[x][1]]+size[son[x][2]]+1;
}
inline void split(int &x,int &y,int k,int pos)//拆树
{
    if(!pos)x=y=0;
    else
    {
        if(val[pos]<=k)//(拆成比k大与不大于k)
        {x=pos;split(son[pos][2],y,k,son[pos][2]);}
        else
        {y=pos;split(x,son[pos][1],k,son[pos][1]);}
        update(pos);
    }
}
inline int merge(int x,int y)//合并
{
    if(x==0||y==0) return x+y;
    if(rnd[x]<rnd[y])//如果rand[x]<rand[y] 我们就把y接在x的右儿子上
    {
        son[x][2]=merge(son[x][2],y);
        update(x);return x;
    }
    else//反之同理
    {
        son[y][1]=merge(x,son[y][1]);
        update(y);return y;
    }
}
inline int find(int pos,int rank)
{
    while(1)//(原理上面已讲)
    {
        if(size[son[pos][1]]>=rank)
        {
            pos=son[pos][1];
        }
        else 
        if(size[son[pos][1]]+1==rank)return pos;
        else
        {
            rank-=size[son[pos][1]]+1;
            pos=son[pos][2];
        }
    }
}
int main()
{
    srand((unsigned)time(NULL));
    int b,x,y,z,op,root=0,m;
    read(n);
    for(register int i=1;i<=n;i++)
    {
        read(op);
        split(x,y,op,root);//拆开
        root=merge(merge(x,newnode(op)),y);//插入,合并回来
    }
    read(m);char a[3]; 
    for(register int i=1;i<=m;i++)
    {
        scanf("%s%d",a,&b);
        if(a[0]=='a')
        {
            split(x,y,b,root);
            root=merge(merge(x,newnode(b)),y);
            n++;//中位数是动态的,所以改变总个数就好了。
        }
        else
        {
            register int mid=(n+1)/2;//加1的原因就不说了
            printf("%d\n",val[find(root,mid)]);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42701791/article/details/81840518