zoukankan      html  css  js  c++  java
  • Treap树模板hdu4585

    例题:hdu 4585

    # Treap树 是一种简单的平衡二叉搜索树。 二叉搜索树的每一个节点都有一个键值,除此之外Treap树为每个节点人为添加了一个称之为优先级的权值。对于键值来说,这是一棵二叉搜索树,对于权值来说这是一个堆。 ## 1、Treap树的唯一性 Treap树的重要特性:另每个节点的优先级互不相等,那么整棵树的形态时唯一的,和元素的插入顺序没有关系。 ## 2、Treap树的平衡问题 树的形态依赖于节点的优先级,那么如何配置每个节点的优先级,才能避免二叉树的形态退化成链表?最简单的方法时把每个节点的优先级进行随机赋值,那么生成的Treap树形态也是随机的。这虽然不能保证每次生成的Treap树一定时平衡的,但是期望的插入、删除、查找的复杂度都是O(logn)的。 ##3、Treap树的数据结构 ```c struct Node{ int size; // 以这个点为根的子树的节点的数量 int rank; // 优先级 int key; // 键值 Node *son[2]; //son[0]时左儿子,son[1]是右儿子 bool operator < (const Node &a)const {return rank < a.rank;} int cmp(int x)const{ if(x == key) return -1; return x < key? 0 : 1; } void update(){ //更新size size = 1; if(son[0] != NULL) size += son[0] -> size; if(son[1] != NULL) size += son[1] -> size; } }; ``` ## 4、Treap树的插入 每读入一个新的节点,为它分配一个随机的优先级,插入到树中,在插入时动态调整树的结构,使它仍然是一棵Treap树。 把新节点插入到Treap树的过程有两步 (1)用朴素的插入方法把node按键值的大小插入到合适的子树上去。

    (2)给node随机分配一个优先级,如果node的优先级违反了堆的性质,即它的优先级比父节点高,那么让node往上走,替代父节点,最后得到一个新的Treap树。

    void insert(Node * &o, int x){  //插入
        if(o == NULL){
            o = new Node();
            o -> son[0] = o -> son[1] = NULL;
            o -> rank = rand();
            o -> key = x;
            o -> size = 1;
        }
        else{
            int d = o -> cmp(x);
            insert(o -> son[d], x);
            o -> update();
            if(o < o -> son[d])
                rotate(o, d^1);
        }
    }
    

    5、插入过程中维护堆的过程中用到的旋转

    void rotate(Node * &o, int d){  // d = 0 左旋,d = 1右旋
        Node *k = o -> son[d^1];  //d^1 == 1 - d
        o -> son[d^1] = k -> son[d];
        k -> son[d] = o;
        o -> update();
        k -> update();
        o = k;
    }
    

    6、寻找第k大的数 O(logn)

    int kth(Node* o, int k){
        if(o == NULL || k <= 0 || k > o -> size)
            return -1;
        int s = o -> son[1] == NULL? 0: o -> son[1] -> size;
        if(k == s + 1) return o -> key;
        else if(k <= s) return kth(o -> son[1], k);
        else return kth(o -> son[0], k - s - 1);
    }
    

    7、查询某个数的名次 O(logn)

    int find(Node* o, int k){
        if(o == NULL) return -1;
        int d = o -> cmp(k);
        if(d == -1)
            return o -> son[1] == NULL? 1: o -> son[1] -> size + 1;
        else if(d == 1) return find(o -> son[d], k);
        else{
            int tmp = find(o -> son[d], k);
            if(tmp == -1) return -1;
            else
                return o -> son[1] == NULL? tmp + 1: tmp + 1 + o -> son[1] -> size;
        }
    }
    

    8、hdu 4585 AC代码

    //#include <bits/stdc++.h>
    #include <iostream>
    #include <stack>
    #include <string>
    #include <queue>
    #include <stack>
    #include <set>
    #include <list>
    #include <map>
    #include <algorithm>
    #include <string.h>
    #include <time.h>
    using namespace std;
    int id[5000000 + 5];
    struct Node{
        int size;  // 以这个点为根的子树的节点的数量
        int rank;  // 优先级
        int key;  // 键值
        Node *son[2];  //son[0]时左儿子,son[1]是右儿子
        bool operator < (const Node &a)const {return rank < a.rank;}
        int cmp(int x)const{
            if(x == key) return -1;
            return x < key? 0 : 1;
        }
        void update(){  //更新size
            size = 1;
            if(son[0] != NULL) size += son[0] -> size;
            if(son[1] != NULL) size += son[1] -> size;
        }
    };
     
    void rotate(Node * &o, int d){  // d = 0 左旋,d = 1右旋
        Node *k = o -> son[d^1];  //d^1 == 1 - d
        o -> son[d^1] = k -> son[d];
        k -> son[d] = o;
        o -> update();
        k -> update();
        o = k;
    }
     
    void insert(Node * &o, int x){  //插入
        if(o == NULL){
            o = new Node();
            o -> son[0] = o -> son[1] = NULL;
            o -> rank = rand();
            o -> key = x;
            o -> size = 1;
        }
        else{
            int d = o -> cmp(x);
            insert(o -> son[d], x);
            o -> update();
            if(o < o -> son[d])
                rotate(o, d^1);
        }
    }
     
    int kth(Node* o, int k){
        if(o == NULL || k <= 0 || k > o -> size)
            return -1;
        int s = o -> son[1] == NULL? 0: o -> son[1] -> size;
        if(k == s + 1) return o -> key;
        else if(k <= s) return kth(o -> son[1], k);
        else return kth(o -> son[0], k - s - 1);
    }
     
    int find(Node* o, int k){
        if(o == NULL) return -1;
        int d = o -> cmp(k);
        if(d == -1)
            return o -> son[1] == NULL? 1: o -> son[1] -> size + 1;
        else if(d == 1) return find(o -> son[d], k);
        else{
            int tmp = find(o -> son[d], k);
            if(tmp == -1) return -1;
            else
                return o -> son[1] == NULL? tmp + 1: tmp + 1 + o -> son[1] -> size;
        }
    }
     
    int main(){
        int n;
        while(~scanf("%d", &n) && n){
            srand(time(NULL));
            int k, g;
            scanf("%d %d", &k, &g);
            Node *root = new Node();
            root -> son[0] = root -> son[1] = NULL;
            root -> rank = rand();
            root -> key = g;
            root -> size = 1;
            id[g] = k;
            printf("%d %d\n", k, 1);
            for(int i = 2; i <= n; i++){
                scanf("%d %d", &k, &g);
                id[g] = k;
                insert(root, g);
                int t = find(root, g);
                int ans1, ans2, ans;
                ans1 = kth(root, t - 1);
                ans2 = kth(root, t + 1);
                if(ans1 != -1 && ans2 != -1){
                    ans = ans1 - g >= g - ans2? ans2: ans1;
                }
                else if(ans1 == -1) ans = ans2;
                else ans = ans1;
                printf("%d %d\n", k, id[ans]);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Cogs 452. Nim游戏!(博弈)
    Cogs 876. 游戏(DP)
    Cogs 2546. 取石块儿(博弈)
    Bzoj 4147: [AMPPZ2014]Euclidean Nim(博弈)
    Codevs 3002 石子归并 3(DP四边形不等式优化)
    洛谷 P1041 传染病控制
    洛谷 P1967 货车运输
    洛谷 P1038 神经网络
    洛谷 P1027 Car的旅行路线
    洛谷 P1054 等价表达式
  • 原文地址:https://www.cnblogs.com/lihello/p/11520750.html
Copyright © 2011-2022 走看看