初探treap

treap的基本操作

treap类似二分查找树,只是加了一个堆,用随机值维护平衡,只是期望平衡。小数据下表现并不是特别优秀,但是足够用了。

先水两发,之后再继续搞- -、

poj1338 Ugly Numbers

把质因子只含2,3,5的数叫Ugly Number.通式为:

x=2i×3j×5k

注意到是一个幂次计算,因此大致地有:

0≤i,j,k≤30

那么我们只需要枚举∏(0≤i≤30,x=2,3,5)xi,然后排序即可。当然也可以直接logn地插入,于是可以用STL的set维护,这里不用set,用Treap维护一下,每个节点还要增加一个rank,用来维护子树节点的数量。

代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;

typedef long long type;
struct node {
    type val;
    int fix;
    int rank; //增加维护一个rank值,保存以该节点为根子树的节点数目
    node* left;
    node* right;
    node() {
        left = right = NULL;
    }
    node(type x) {
        val = x;
        fix = rand();
        left = right = NULL;
    }
};

inline int rank(node* &T) {
    return T == NULL ? 0 : T->rank;
}

void rotate_left(node* &T) {
    //printf("rotate_left %d\n", T->val);
    node* tp = T->right;
    T->right = tp->left;
    T->rank = rank(T->left) + rank(T->right) + 1;
    tp->left = T;
    tp->rank = rank(tp->left) + rank(tp->right) + 1;
    T = tp;
}

void rotate_right(node* &T) {
    //printf("rotate_right %d\n", T->val);
    node* tp = T->left;
    T->left = tp->right;
    T->rank = rank(T->left) + rank(T->right) + 1;
    tp->right = T;
    tp->rank = rank(tp->left) + rank(tp->right) + 1;
    T = tp;
}

void insert(node* &T, type& val) {
    if (T == NULL) {
        T = new node(val);
        T->rank = 1;
    } else if (val == T->val) {
        return;
    } else if (val < T->val) {
        insert(T->left, val);
        ++T->rank;
        if (T->left->fix < T->fix) {
            rotate_right(T);
        }
    } else {
        insert(T->right, val);
        ++T->rank;
        if (T->right->fix < T->fix) {
            rotate_left(T);
        }
    }
}

void erase(node* &T, type& val) {
    if (val == T->val) {
        if (T->left == NULL || T->right == NULL) {
            node* t = T;
            if (T->left == NULL) {
                T = T->right;
            } else {
                T = T->left;
            }
            T->rank = rank(T->left) + rank(T->right) + 1;
            delete t;
        } else {
            if (T->left->fix < T->right->fix) {
                rotate_right(T);
                erase(T->right, val);
            } else {
                rotate_left(T);
                erase(T->left, val);
            }
        }
    } else if (val < T->val) {
        erase(T->left, val);
        --(T->rank);
    } else {
        erase(T->right, val);
        --(T->rank);
    }
}

bool exist(node* &T, type val) {
    if (T == NULL) {
        return false;
    } else if (T->val == val) {
        return true;
    } else if (val < T->val) {
        return exist(T->left, val);
    } else {
        return exist(T->right, val);
    }
}

void clear(node* &T) {
    if (T == NULL) return;
    clear(T->left);
    clear(T->right);
    delete T;
    T = NULL;
}

const type INF = 0xfffffff;
type find_k(node* &T, int k) {
    //printf("find_k(%d)\n", k);
    if (k <= 0 || k > rank(T)) {
        return INF;
    } else if (k == rank(T->left) + 1) {
        return T->val;
    } else if (k <= rank(T->left)) {
        return find_k(T->left, k);
    } else {
        return find_k(T->right, k - 1 - rank(T->left));
    }
}

void visit(node* &T) {
    if (T == NULL) return;
    visit(T->left);
    printf("(%d,%d) ", T->val, T->rank);
    visit(T->right);
}

const int MAX = 32;
type p2[MAX], p3[MAX], p5[MAX];

int main() {
    p2[0] = p3[0] = p5[0] = 1;
    for (int i = 1; i < MAX; ++i) {
        p2[i] = p2[i - 1] << 1;
        p3[i] = p3[i - 1] * 3;
        p5[i] = p5[i - 1] * 5;
    }
    node* T = NULL;
    for (int i = 0; i < MAX; ++i) {
        if (p2[i] <= 0) break;
        for (int j = 0; j < MAX; ++j) {
            if (p3[j] <= 0) break;
            for (int k = 0; k < MAX; ++k) {
                long long t = p2[i] * p3[j] * p5[k];
                if (t <= 0) break;
                //printf("insert %d\n", t);
                insert(T, t);
            }
        }
    }
    //visit(T);
    //puts("");

    int n;
    while (~scanf(" %d", &n)) {
        if (n == 0) break;
        printf("%lld\n", find_k(T, n));
    }
    clear(T);

    return 0;
}

poj1552

这题只需要用到查找操作,遍历维护的treap,对任意节点x只需要检查是否存在元素2×x即可。代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;

typedef int type;
struct node {
    type val;
    int fix;
    node* left;
    node* right;
    node() {
        left = right = NULL;
    }
    node(type x) {
        val = x;
        fix = rand();
        left = right = NULL;
    }
};

void rotate_left(node* &T) {
    node* tp = T->right;
    T->right = tp->left;
    tp->left = T;
    T = tp;
}

void rotate_right(node* &T) {
    node* tp = T->left;
    T->left = tp->right;
    tp->right = T;
    T = tp;
}

void insert(node* &T, type& val) {
    if (T == NULL) {
        T = new node(val);
    } else if (val <= T->val) {
        insert(T->left, val);
        if (T->left->fix < T->fix) {
            rotate_right(T);
        }
    } else {
        insert(T->right, val);
        if (T->right->fix < T->fix) {
            rotate_left(T);
        }
    }
}

void erase(node* &T, type& val) {
    if (val == T->val) {
        if (T->left == NULL || T->right == NULL) {
            node* t = T;
            if (T->left == NULL) {
                T = T->right;
            } else {
                T = T->left;
            }
            delete t;
        } else {
            if (T->left->fix < T->right->fix) {
                rotate_right(T);
                erase(T->right, val);
            } else {
                rotate_left(T);
                erase(T->left, val);
            }
        }
    } else if (val < T->val) {
        erase(T->left, val);
    } else {
        erase(T->right, val);
    }
}

bool exist(node* &T, type val) {
    if (T == NULL) {
        return false;
    } else if (T->val == val) {
        return true;
    } else if (val < T->val) {
        return exist(T->left, val);
    } else {
        return exist(T->right, val);
    }
}

void clear(node* &T) {
    if (T == NULL) return;
    clear(T->left);
    clear(T->right);
    delete T;
    T = NULL;
}

int query(node* &root, node* &T) {
    if (T == NULL) return 0;
    return exist(root, (T->val) * 2)
        + query(root, T->left) + query(root, T->right);
}

void visit(node* &T) {
    if (T == NULL) return;
    visit(T->left);
    printf("%d ", T->val);
    visit(T->right);
}

int main() {
    node* T = NULL;
    int n;
    while (~scanf(" %d", &n) && n != - 1) {
        while (n != 0) {
            insert(T, n);
            //visit(T);
            //puts("");
            scanf(" %d", &n);
        }
        printf("%d\n", query(T, T));
        clear(T);
    }
    return 0;
}

HDU5058 So easy

题意类似判断两个集合是否相等。即是否一个数组中的元素在另一个元素中也一定存在。去重后比较即可。但是,同样地,用treap来练习…

代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;

typedef int type;
struct node {
    type val;
    int fix;
    node* left;
    node* right;
    node() {
        left = right = NULL;
    }
    node(type x) {
        val = x;
        fix = rand();
        left = right = NULL;
    }
};

void rotate_left(node* &T) {
    node* tp = T->right;
    T->right = tp->left;
    tp->left = T;
    T = tp;
}

void rotate_right(node* &T) {
    node* tp = T->left;
    T->left = tp->right;
    tp->right = T;
    T = tp;
}

void insert(node* &T, type& val) {
    if (T == NULL) {
        T = new node(val);
    } else if (val == T->val) {
        return;
    } else if (val < T->val) {
        insert(T->left, val);
        if (T->left->fix < T->fix) {
            rotate_right(T);
        }
    } else {
        insert(T->right, val);
        if (T->right->fix < T->fix) {
            rotate_left(T);
        }
    }
}

void erase(node* &T, type& val) {
    if (val == T->val) {
        if (T->left == NULL || T->right == NULL) {
            node* t = T;
            if (T->left == NULL) {
                T = T->right;
            } else {
                T = T->left;
            }
            delete t;
        } else {
            if (T->left->fix < T->right->fix) {
                rotate_right(T);
                erase(T->right, val);
            } else {
                rotate_left(T);
                erase(T->left, val);
            }
        }
    } else if (val < T->val) {
        erase(T->left, val);
    } else {
        erase(T->right, val);
    }
}

bool exist(node* &T, type val) {
    if (T == NULL) {
        return false;
    } else if (T->val == val) {
        return true;
    } else if (val < T->val) {
        return exist(T->left, val);
    } else {
        return exist(T->right, val);
    }
}

void clear(node* &T) {
    if (T == NULL) return;
    clear(T->left);
    clear(T->right);
    delete T;
    T = NULL;
}

bool query(node* &root, node* &T) {
    if (T == NULL) return true;
    return exist(root, T->val)
        && query(root, T->left) && query(root, T->right);
}

int main() {
    int n;
    type x;
    node* T1 = NULL, *T2 = NULL;
    while (~scanf(" %d", &n)) {
        for (int i = 0; i < n; ++i) {
            scanf(" %d", &x);
            insert(T1, x);
        }
        for (int i = 0; i < n; ++i) {
            scanf(" %d", &x);
            insert(T2, x);
        }
        puts(query(T1, T2) && query(T2, T1) ? "YES" : "NO");
        clear(T1);
        clear(T2);
    }
    return 0;
}
时间: 2024-08-15 16:14:14

初探treap的相关文章

Treap

先推荐一篇文章和黄学长的代码http://hzwer.com/1712.html    https://wenku.baidu.com/view/c8c11e1e650e52ea55189887.html 黄学长的代码既不用指针又很短,真心推荐 Treap,顾名思义,Tree+Heap,它既满足二叉搜索树的性质,又满足堆的性质 对于二叉搜索树,如果我们把数有序加入,那么它的时间效率会退化成O(n). 我们引入一个随机数(即下文描述的修正值),使得随机数满足堆的性质(小根堆或大根堆,不一定要是完全

进阶之初探nodeJS

一.前言 在"初探nodeJS"随笔中,我们对于node有了一个大致地了解,并在最后也通过一个示例,了解了如何快速地开启一个简单的服务器. 今儿,再次看了该篇随笔,发现该随笔理论知识稍多,适合初级入门node,固萌生一个想法--想在该篇随笔中,通过一步步编写一个稍大一点的node示例,让我们在整体上更加全面地了解node. so,该篇随笔是建立在"初探nodeJS"之上的,固取名为"进阶之初探nodeJS". 好了,侃了这多,那么我们即将实现一个

【贪心+Treap】BZOJ1691-[Usaco2007 Dec]挑剔的美食家

[题目大意] 有n头奶牛m种牧草,每种牧草有它的价格和鲜嫩度.每头奶牛要求它的牧草的鲜嫩度要不低于一个值,价格也不低于一个值.每种牧草只会被一头牛选择.问最少要多少钱? [思路] 显然的贪心,把奶牛和牧草都按照鲜嫩度由大到小排序,对于每奶牛把鲜嫩度大于它的都扔进treap,然后找出后继. 不过注意后继的概念是大于它且最小的,然而我们这里是可以等于的,所以应该是找cow[i].fresh-1的后继,注意一下…… 1 #include<iostream> 2 #include<cstdio&

从273二手车的M站点初探js模块化编程

前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数据. 273这个M站点是产品推荐我看的.第一眼看这个产品时我就再想他们这个三次加载和翻页按钮的方式,那么小分页的pageIndex是怎么计算的.所以就顺便看了下源码. 提到看源码时用到了Chrome浏览器的格式化工具(还是朋友推荐我的,不过这个格式化按钮的确不明显,不会的话自行百度). 三次加载和分

[转载]HDFS初探之旅

转载自 http://www.cnblogs.com/xia520pi/archive/2012/05/28/2520813.html , 感谢虾皮工作室这一系列精彩的文章. Hadoop集群(第8期)_HDFS初探之旅 1.HDFS简介 HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上.它所具有的高容错.高可靠性.高可扩展性.高

MongoDB初探系列之二:认识MongoDB提供的一些常用工具

在初探一中,我们已经可以顺利的将MongoDB在我们自己的机器上跑起来了.但是在其bin目录下面还有一些我们不熟知的工具.接下来,将介绍一下各个小工具的用途以及初探一中MongoDB在data文件夹下创建的文件的用途. 1.bin目录下面的各种小工具简介及使用方式 bsondump.exe 用于将导出的BSON文件格式转换为JSON格式mongo.exe mongoDB的客户端 mongod.exe 用于启动mongoDB的Server mongodump.exe 用于从mongodb数据库中导

1503: [NOI2004]郁闷的出纳员 Treap

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 6263  Solved: 2190[Submit][Status] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可

Asynchronous Pluggable Protocols 初探

Asynchronous Pluggable Protocols,异步可插入协议,允许开发者创建可插协议处理器,MIME过滤器,以及命名空间处理器工作在微软IE4.0浏览器以及更高版本或者URL moniker中.这涉及到Urlmon.dll动态链接库所公开(输出)的可插协议诸多功能,本文不进行深入的原理讲解,只对它其中之一的应用进行解析,那就是如何将一个应用程序注册为URL协议. 应用场景: tencent协议: 当我们打开"tencent://message/?uin=要链接的QQ号 &qu

重新认识HTML,CSS,Javascript 之node-webkit 初探

今天我们来系统的.全面的 了解一下前端的一些技术,将有助于我们写出 更优秀的 产品 出来. 什么是HTML? HTML 是用来描述网页的一种语言. HTML 包含一些根节点,子节点,文本节点,属性节点,组成, 它通过一系列预定义标签来描述网页结构,如: <title>This is title</title> ,这个表明该网页的标题是 This is title. 什么是CSS? CSS 指层叠样式表 (Cascading Style Sheets),它描述浏览器显示如何显示htm