zoukankan      html  css  js  c++  java
  • fhq-treap小结

    终于AC fhq-Treap啦!!!撒花庆祝qwq

    回头看看fhq-treap真的吼哇!

    推一波大佬的博客:https://www.cnblogs.com/ppprseter/p/9382132.html

    就是看这个学会的qwq

    进入正题:

    fhq-treap,也具有Treap的性质,即堆+bst的性质,在此基础上,它不需要进行旋转以维护平衡,而是用拆树和合并的操作让树保持平衡

    支持区间、效率高、可持久化!

    规定如下:

      val:按平衡树的权值

      key:按堆的权值

      sz:子树大小

      root:当前根

      ch[now][0] : 左儿子,ch[now][1]右儿子

      #define ls ch[now][0]    rs ch[now][1]

    操作1:split(拆树)

      将一个树拆成两个:

    void split(int now,int k,int &x,int &y)//x <= k,y > k
    {
        if(!now) 
        {        
            x = y = 0;
            return;
        }
        if(val[now] <= k) x = now,split(rs,k,rs,y);
        else y = now,split(ls,k,x,ls);
        update(now);
    }

        函数意义为:以now为根,将树拆成两部分,x部的权值全部<=k,y部>k    

        考虑当前节点now:如果val[now]<=k,那么now的左子树应当被分配给x(十分显然qwq),而now的右子树不确定,同时x的右子树也不确定,而y未被分配,因此进入下一层求解。>k同理

    操作2:merge(合并)

      将两个树合并,返回新树的根:

    int merge(int x,int y)//val:x <= y 
    {
        if(!x || !y) return x + y;
        if(key[x] < key[y])
        {
            ch[x][1] = merge(ch[x][1],y);
            update(x);
            return x;
        }
        else 
        {
            ch[y][0] = merge(x,ch[y][0]);
            update(y);
            return y;
        }
    }

         规定:val[x] < val[y]  

         如果x和y中有一个为空,那么返回另一个即可

         由于x,y是由split得来,因此二者均是bst,因此在合并时,只用考虑堆性质即可

    有了这两个,其他的操作就围绕他们来:

      新建点:不多说

    int New(int k)
    {
        key[++tot] = rand(),val[tot] = k,sz[tot] = 1;
        return tot;
    }

      插入:  

        先将树按插入数大小k分成两份,把k加到x中,再把树合并回去:

    void insert(int k)
    {
        int x,y;
        split(root,k,x,y);
        root = merge(merge(x,New(k)),y);
    }

      删除:

        先把树按要删的数k分成x,y,此时x中所有数<=k,再把x按k-1分成x和z,此时z中所有数都等于k,删去z的根,就把z的左右儿子合并(相当于抛弃了z的根节点),然后再合并回去即可

    void del(int k)
    {
        int x,y,z;
        split(root,k,x,y);
        split(x,k - 1,x,z);
        z = merge(ch[z][0],ch[z][1]);
        root = merge(x,merge(z,y));
    }

       查k的排名:

        把树按k - 1分成两份(注意!不能按k分,由于可能有重,按k分无法得到正解),此时x部<=k - 1,y部>=k,输出x部大小即可

    void Rank(int k)
    {
        int x,y;
        split(root,k - 1,x,y);
        printf("%d
    ",sz[x] + 1);
        root = merge(x,y);
    }

        找第k大:

          与Treap相同

    void fRank(int now,int k)
    {
        while(1)
        {
            if(k <= sz[ls]) now = ls;
            else if(k > sz[ls] + 1) k -= sz[ls] + 1,now = rs;
            else { printf("%d
    ",val[now]); return;}
        }
    }

         前后继:

           由拆分和合并易得

    传送门:https://www.luogu.org/problemnew/show/P3369

    总体代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<climits>
    #include<vector>
    #include<cstdlib>
    #include<ctime>
    using namespace std;
    #define ls ch[now][0]
    #define rs ch[now][1]
    inline int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (ans *= 10) += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    const int maxn = 1e5 + 5;
    int sz[maxn],key[maxn],val[maxn],tot,ch[maxn][2],root;//key:堆相关;val:树相关 
    inline void update(int now)
    {
        sz[now] = sz[ls] + sz[rs] + 1;
    }
    void split(int now,int k,int &x,int &y)//x <= k,y > k
    {
        if(!now) 
        {        
            x = y = 0;
            return;
        }
        if(val[now] <= k) x = now,split(rs,k,rs,y);
        else y = now,split(ls,k,x,ls);
        update(now);
    }
    int merge(int x,int y)//val:x <= y 
    {
        if(!x || !y) return x + y;
        if(key[x] < key[y])
        {
            ch[x][1] = merge(ch[x][1],y);
            update(x);
            return x;
        }
        else 
        {
            ch[y][0] = merge(x,ch[y][0]);
            update(y);
            return y;
        }
    }
    int New(int k)
    {
        key[++tot] = rand(),val[tot] = k,sz[tot] = 1;
        return tot;
    }
    void insert(int k)
    {
        int x,y;
        split(root,k,x,y);
        root = merge(merge(x,New(k)),y);
    }
    void del(int k)
    {
        int x,y,z;
        split(root,k,x,y);
        split(x,k - 1,x,z);
        z = merge(ch[z][0],ch[z][1]);
        root = merge(x,merge(z,y));
    }
    void Rank(int k)
    {
        int x,y;
        split(root,k - 1,x,y);
        printf("%d
    ",sz[x] + 1);
        root = merge(x,y);
    }
    void fRank(int now,int k)
    {
        while(1)
        {
            if(k <= sz[ls]) now = ls;
            else if(k > sz[ls] + 1) k -= sz[ls] + 1,now = rs;
            else { printf("%d
    ",val[now]); return;}
        }
    }
    void pre(int k)
    {
        int x,y;
        split(root,k - 1,x,y);
        fRank(x,sz[x]);
        root = merge(x,y);
    }
    void suc(int k)
    {
        int x,y;
        split(root,k,x,y);
        fRank(y,1);
        root = merge(x,y);
    }
    int main()
    {
        int n = read();
        int opt,x;
        while(n--)
        {
            opt = read(),x = read(); 
            if(opt == 1) insert(x);
            if(opt == 2) del(x);
            if(opt == 3) Rank(x); 
            if(opt == 4) fRank(root,x);
            if(opt == 5) pre(x);
            if(opt == 6) suc(x); 
        }
        return 0;
    }

        

  • 相关阅读:
    streamsets 集成 cratedb 测试
    streamsets k8s 部署试用
    streamsets rest api 转换 graphql
    StreamSets sdc rpc 测试
    StreamSets 相关文章
    StreamSets 多线程 Pipelines
    StreamSets SDC RPC Pipelines说明
    StreamSets 管理 SDC Edge上的pipeline
    StreamSets 部署 Pipelines 到 SDC Edge
    StreamSets 设计Edge pipeline
  • 原文地址:https://www.cnblogs.com/LM-LBG/p/10331476.html
Copyright © 2011-2022 走看看