树堆Treap、伸展树Splay Tree

//Treap树堆
struct Treap {
    struct Node {
        Node *ch[2];
        int prio, val;
        int cmp(int x) {
            if (x == val) return -1;
            return val < x;
        }
        //优先级比较
    };
    Node *root = NULL;
    void insert(int x) { if (!find(x)) insert(root, x); }
    void remove(int x) { if (find(x)) remove(root, x); }

    bool cmp_prio(Node *a, Node *b) { return a->prio < b->prio; }
    int cmp_val(Node *a, Node *b) { return a->val < b->val; }//小于往左,大于等于往右
    void rotate(Node *&o, int f) {//f==0代表左旋 1代表右旋
        Node *k = o->ch[f ^ 1];
        o->ch[f ^ 1] = k->ch[f], k->ch[f] = o; o = k;
    }
    void insert(Node *&o, int x) {
        if (o == NULL) {
            o = new Node();
            o->ch[0] = o->ch[1] = NULL; o->val = x, o->prio = rand();
        }
        else {
            int k = o->cmp(x);
            if (k == -1)
                printf("已存在\n");
            else {
                insert(o->ch[k], x);
                if (o->ch[k]->prio > o->prio)
                    rotate(o, k ^ 1);
            }
        }
    }
    void remove(Node *&o, int x) {
        int k = o->cmp(x);
        if (k == -1) {
            Node *old = o;
            if (o->ch[0] == NULL) o = o->ch[1], delete(old);
            else if (o->ch[1] == NULL) o = o->ch[0], delete(old);
            else {
                int d = o->ch[0]->prio < o->ch[1]->prio;//d==0代表左子树优先级大,要右旋。。。
                rotate(o, d ^ 1); remove(o->ch[d ^ 1], x);
            }
        }
    }
    int find(int x) {
        Node *o = root;
        while (o != NULL) {
            int k = o->cmp(x);
            if (k == -1)return 1;//存在
            else o = o->ch[k];
        }
        return 0;//不存在
    }
};
//*********************伸展树
struct ST {
    struct Node {
        Node *ch[2];
        int n;//以此结点为根的树的结点数
        void maintain() {
            n = 1;
            if (ch[0]) n += ch[0]->n;
            if (ch[1]) n += ch[1]->n;
        }
        int get_id() {
            int l = 1;
            if (ch[0]) l += ch[0]->n;//l代表当前结点是第几个
            return l;
        }
        int cmp(int x) {
            int l = get_id();
            if (l == x) return -1;
            return l < x;
        }
    };
    Node *root=NULL;
    void rotate(Node *&o, int f) {//f==0代表左旋 1代表右旋
        Node *k = o->ch[f ^ 1];
        o->ch[f ^ 1] = k->ch[f], k->ch[f] = o; o = k;
        o->maintain();
    }
    void splay(Node *&o, int k) {//找到从左数第k个元素并伸展到跟
        int d1 = o->cmp(k);
        if (d1 == 1) k -= o->get_id();//在右子树上
        if (d1 != -1) {
            Node *p = o->ch[d1];//在p树上寻找
            int d2 = p->cmp(k);
            if (d2 == 1) k -= p->get_id();
            if (d2 != -1) {
                splay(p->ch[d2], k);
                if (d1 == d2) rotate(o, d1 ^ 1);
                else rotate(o->ch[d1], d1);//不能用p代替ch[d1]!!!
            }
            rotate(o, d1 ^ 1);
        }
    }
    Node* merge(Node* left, Node* right) {
        splay(left, left->n);
        left->ch[1] = right;
        left->maintain();
        return left;
    }
    void split(Node* o, int k, Node *&left, Node* &right) {
        splay(o, k);
        left = o;
        right = o->ch[1];
        left->ch[1] = NULL;
        left->maintain();
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值