1 条题解

  • 0
    @ 2025-8-24 21:53:36

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 陈曦
    **

    搬运于2025-08-24 21:53:36,当前版本为作者最后更新于2018-08-01 21:34:15,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


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

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

    至于不会fhq treap的同学可以先点这里或者这里记得点赞

    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)]);
            }
        }
    }
    

    如果各位大佬觉得讲的还行,请赏一个赞,谢谢。

    • 1

    信息

    ID
    2828
    时间
    1000ms
    内存
    125MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者