Treap树模板hdu-4585

目录

  • 例题:hdu 4585
  • Treap树
    • 1、Treap树的唯一性
    • 2、Treap树的平衡问题
    • 3、Treap树的数据结构
    • 4、Treap树的插入
    • 5、插入过程中维护堆的过程中用到的旋转
    • 6、寻找第k大的数 O(logn)
    • 7、查询某个数的名次 O(logn)
    • 8、hdu 4585 AC代码

例题:hdu 4585

Treap树

是一种简单的平衡二叉搜索树。
二叉搜索树的每一个节点都有一个键值,除此之外Treap树为每个节点人为添加了一个称之为优先级的权值。对于键值来说,这是一棵二叉搜索树,对于权值来说这是一个堆。

1、Treap树的唯一性

Treap树的重要特性:另每个节点的优先级互不相等,那么整棵树的形态时唯一的,和元素的插入顺序没有关系。

2、Treap树的平衡问题

树的形态依赖于节点的优先级,那么如何配置每个节点的优先级,才能避免二叉树的形态退化成链表?最简单的方法时把每个节点的优先级进行随机赋值,那么生成的Treap树形态也是随机的。这虽然不能保证每次生成的Treap树一定时平衡的,但是期望的插入、删除、查找的复杂度都是O(logn)的。

3、Treap树的数据结构

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

原文地址:https://www.cnblogs.com/lihello/p/11520750.html

时间: 2024-10-08 11:32:30

Treap树模板hdu-4585的相关文章

treap树模板

1 ///treap树模板 2 typedef struct Node ///节点的结构体 3 { 4 Node *l,*r; 5 int val,pri; ///节点的值和优先级 6 int sz; ///节点子树的节点数 7 Node(int x) ///初始化节点 8 { 9 l=r=NULL; 10 val=x; 11 pri=rand(); 12 sz=1; 13 } 14 }Node; 15 Node *root; 16 17 int Tsize(Node *T) ///计算子树的叶

字典树模板 [HDU 1251] 统计难题

统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)Total Submission(s): 19054    Accepted Submission(s): 8418 Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前

线段树模板hdu 1754:I Hate It

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 100523    Accepted Submission(s): 37845 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的

字典树模板+HDU 1671 ( Phone List )(字典树)

字典树指针模板(数组模板暂时还没写): 1 #include<cstdio> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int MAX=26; 6 const int maxn=1e4+100; 7 int N; 8 9 struct Trie 10 { 11 Trie *next[MAX]; 12 int v;///v要灵活使用,具体情况具体分析 13 }; 14

POJ 1442 Black Box(treap树)

题目链接:点击打开链接 思路:treap树模板题, 可以动态维护一个有序表, 支持在O(logN)的时间内完成插入.删除一个元素和查找第K大元素的任务. 当然, treap树能做到的还远远不止这些, 常常与其他数据结构嵌套. treap树是一种平衡二叉搜索树, 既满足堆的条件, 又满足排序二叉树的条件. 细节参见代码: #include <cstdio> #include <cstring> #include <algorithm> #include <iostr

HDU 1251 Trie树模板题

1.HDU 1251 统计难题  Trie树模板题,或者map 2.总结:用C++过了,G++就爆内存.. 题意:查找给定前缀的单词数量. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b #define F(i,a,b

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

hdu 4819 二维线段树模板

/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1010; int N, Q; struct Nodey { int l, r; int Max, Min; }; int locx[MAXN], l

HDU 4585 Shaolin(Treap找前驱和后继)

Shaolin Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 3191    Accepted Submission(s): 1350 Problem Description Shaolin temple is very famous for its Kongfu monks.A lot of young men go to Shao