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

    (fhq-treap)

    复习一下fhq-treap

    fhp-treap 就是一种不旋转的treap,所以也就有treap的性质——BST + 堆,然后用拆分+合并代替treap的旋转操作

    其优点在于:

    支持区间,效率高,可持久化

    下面是需要的变量

    val : 按树的平衡权值
    key : 按堆的权值
    sz  : 子树大小
    rt  : 当前根
    ch[now][0] : 左儿子  ch[now][1] 右儿子
    #define ls ch[now][0]
    #define rs ch]now][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部的权值全部 (leq) k, y部全 > k

    考虑当前节点now:

    • 如果val[now] (leq) k:

      ​ 那么now的左子树应当被分给x(较为显然QwQ),而now的右子树不确定,同时x的右子树也不确定,而y未被分配,因此进入下一层求解。

    • val[now] > k 同理

    操作二 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,因此在合并时,只需要考虑堆的性质即可

    然后剩下的操作就围绕着这两个操作展开

    ** 新建点:这个不用多说,与treap一样 **

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

    插入一个数k:

    ​ 先把树按照k拆成两份(x,y),把k加到x中,再把树合并回去

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

    删除一个数k:

    ​ 先把树按k拆分成两份(x,y),这时x中所有的数都(leq)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部(leq) 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;}
        }
    }
    

    前后继:

    由拆分和合并易得

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

    总代码放一个w

    #include<cstdio>
    #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;
    inline void update(int now){
        sz[now] = sz[ls] + sz[rs] + 1;}
    void split(int now,int k,int &x,int &y){
        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){
        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;
    }
    
  • 相关阅读:
    COS和CDN的关系
    【转】WebGL 着色器和GLSL
    【转】前端最新性能指标
    【转】理解音视频 PTS 和 DTS
    HLS
    【转】带有function的JSON对象的序列化与还原
    环信Demo 导入错误
    安卓中 使用html来使文字变色Html.fromHtml
    第三方下载控件 用起来还是不错的偶!Aria
    网络文件下载
  • 原文地址:https://www.cnblogs.com/excellent-zzy/p/12207475.html
Copyright © 2011-2022 走看看