zoukankan      html  css  js  c++  java
  • Treap

    (Treap) 是平衡树的一种,(Treap)(Tree)(Heap) 的组合

    核心思想

    每个节点有两个属性 (key)(val) 其中的 key 满足 BST 二叉搜索树的性质,其中序遍历是一个有序序列。val 满足 Heap 堆的性质,一个节点的 (val) 值大于其孩子节点的 (val)

    随机分配 (val) 使得 期望的 (BST) 是平均深度的

    结构定义

    struct Node{
        int l, r;
        int key, val;//key是BST关键字, val是Heap关键字
        int cnt, size;
    }tr[N];
    
    int root, idx;
    

    节点分配

    int get_node(int key){
        tr[ ++ idx].key = key;
        tr[idx].val = rand(); //随机数据
        tr[idx].cnt = tr[idx].size = 1;
        return idx;
    }
    

    插入操作

    void insert(int &p, int key)
    {
        if (!p) p = get_node(key);
        else if (tr[p].key == key) tr[p].cnt ++ ;
        else if (tr[p].key > key)
        {
            insert(tr[p].l, key);
            if (tr[tr[p].l].val > tr[p].val) zig(p);//右旋
        }
        else
        {
            insert(tr[p].r, key);
            if (tr[tr[p].r].val > tr[p].val) zag(p);//左旋
        }
        pushup(p);
    }
    

    删除操作

    void remove(int &p, int key)
    {
        if (!p) return;
        if (tr[p].key == key)
        {
            if (tr[p].cnt > 1) tr[p].cnt -- ;
            else if (tr[p].l || tr[p].r)
            {
                if (!tr[p].r || tr[tr[p].l].val > tr[tr[p].r].val)
                {
                    zig(p);
                    remove(tr[p].r, key);
                }
                else
                {
                    zag(p);
                    remove(tr[p].l, key);
                }
            }
            else p = 0;
        }
        else if (tr[p].key > key) remove(tr[p].l, key);
        else remove(tr[p].r, key);
    
        pushup(p);
    }
    

    旋转操作

    void zig(int &p)    // 右旋
    {
        int q = tr[p].l;
        tr[p].l = tr[q].r, tr[q].r = p, p = q;
        pushup(tr[p].r), pushup(p);
    }
    
    void zag(int &p)    // 左旋
    {
        int q = tr[p].r;
        tr[p].r = tr[q].l, tr[q].l = p, p = q;
        pushup(tr[p].l), pushup(p);
    }
    

    模板

    普通平衡树

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 100010, INF = 1e8;
    
    int n;
    struct Node
    {
        int l, r;
        int key, val;//key是BST关键字, val是Heap关键字
        int cnt, size;
    }tr[N];
    
    int root, idx;
    
    void pushup(int p)
    {
        tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + tr[p].cnt;
    }
    
    int get_node(int key)
    {
        tr[ ++ idx].key = key;
        tr[idx].val = rand(); //随机数据
        tr[idx].cnt = tr[idx].size = 1;
        return idx;
    }
    
    void zig(int &p)    // 右旋
    {
        int q = tr[p].l;
        tr[p].l = tr[q].r, tr[q].r = p, p = q;
        pushup(tr[p].r), pushup(p);
    }
    
    void zag(int &p)    // 左旋
    {
        int q = tr[p].r;
        tr[p].r = tr[q].l, tr[q].l = p, p = q;
        pushup(tr[p].l), pushup(p);
    }
    
    void build()
    {
        get_node(-INF), get_node(INF);
        root = 1, tr[1].r = 2;
        pushup(root);
        if (tr[1].val < tr[2].val) zag(root);
    }
    
    
    void insert(int &p, int key)
    {
        if (!p) p = get_node(key);
        else if (tr[p].key == key) tr[p].cnt ++ ;
        else if (tr[p].key > key)
        {
            insert(tr[p].l, key);
            if (tr[tr[p].l].val > tr[p].val) zig(p);
        }
        else
        {
            insert(tr[p].r, key);
            if (tr[tr[p].r].val > tr[p].val) zag(p);
        }
        pushup(p);
    }
    
    void remove(int &p, int key)
    {
        if (!p) return;
        if (tr[p].key == key)
        {
            if (tr[p].cnt > 1) tr[p].cnt -- ;
            else if (tr[p].l || tr[p].r)
            {
                if (!tr[p].r || tr[tr[p].l].val > tr[tr[p].r].val)
                {
                    zig(p);
                    remove(tr[p].r, key);
                }
                else
                {
                    zag(p);
                    remove(tr[p].l, key);
                }
            }
            else p = 0;
        }
        else if (tr[p].key > key) remove(tr[p].l, key);
        else remove(tr[p].r, key);
    
        pushup(p);
    }
    
    int get_rank_by_key(int p, int key)    // 通过数值找排名
    {
        if (!p) return 0;   // 本题中不会发生此情况
        if (tr[p].key == key) return tr[tr[p].l].size + 1;
        if (tr[p].key > key) return get_rank_by_key(tr[p].l, key);
        return tr[tr[p].l].size + tr[p].cnt + get_rank_by_key(tr[p].r, key);
    }
    
    int get_key_by_rank(int p, int rank)   // 通过排名找数值
    {
        if (!p) return INF;     // 本题中不会发生此情况
        if (tr[tr[p].l].size >= rank) return get_key_by_rank(tr[p].l, rank);
        if (tr[tr[p].l].size + tr[p].cnt >= rank) return tr[p].key;
        return get_key_by_rank(tr[p].r, rank - tr[tr[p].l].size - tr[p].cnt);
    }
    
    int get_prev(int p, int key)   // 找到严格小于key的最大数
    {
        if (!p) return -INF;
        if (tr[p].key >= key) return get_prev(tr[p].l, key);
        return max(tr[p].key, get_prev(tr[p].r, key));
    }
    
    int get_next(int p, int key)    // 找到严格大于key的最小数
    {
        if (!p) return INF;
        if (tr[p].key <= key) return get_next(tr[p].r, key);
        return min(tr[p].key, get_next(tr[p].l, key));
    }
    
    int main()
    {
        build();
    
        scanf("%d", &n);
        while (n -- )
        {
            int opt, x;
            scanf("%d%d", &opt, &x);
            if (opt == 1) insert(root, x);
            else if (opt == 2) remove(root, x);
            else if (opt == 3) printf("%d
    ", get_rank_by_key(root, x) - 1);
            else if (opt == 4) printf("%d
    ", get_key_by_rank(root, x + 1));
            else if (opt == 5) printf("%d
    ", get_prev(root, x));
            else printf("%d
    ", get_next(root, x));
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    使用 yo 命令行向导给 SAP UI5 应用添加一个新的视图
    SAP Fiori Elements 应用的 manifest.json 文件运行时如何被解析的
    SAP UI5 标准应用的多语言支持
    微软 Excel 365 里如何设置下拉菜单和自动高亮成指定颜色
    SAP Fiori Elements 应用里的 Title 显示的内容是从哪里来的
    本地开发好的 SAP Fiori Elements 应用,如何部署到 ABAP 服务器上?
    如何在 Cypress 测试代码中屏蔽(Suppress)来自应用代码报出的错误消息
    教你一招:让集群慢节点无处可藏
    应用架构步入“无服务器”时代 Serverless技术迎来新发展
    MySQL数据库事务隔离性的实现
  • 原文地址:https://www.cnblogs.com/sduwh/p/13958538.html
Copyright © 2011-2022 走看看