模板 - 无旋Treap-程序员宅基地

普通平衡树:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls(p) ch[p][0]
#define rs(p) ch[p][1]

const int MAXN = 100000 + 5;
int val[MAXN], ch[MAXN][2], rnd[MAXN], siz[MAXN], tot, root;

void Init() {
    tot = root = 0;
}

void PushUp(int p) {
    siz[p] = siz[ls(p)] + siz[rs(p)] + 1;
}

void SplitValue(int p, int v, int &x, int &y) {
    if(!p) {
        x = y = 0;
        return;
    }
    if(v < val[p]) {
        y = p;
        SplitValue(ls(p), v, x, ls(p));
        PushUp(y);
    } else {
        x = p;
        SplitValue(rs(p), v, rs(p), y);
        PushUp(x);
    }
}

void SplitRank(int p, int rk, int &x, int &y) {
    if(!p) {
        x = y = 0;
        return;
    }
    if(rk <= siz[ls(p)]) {
        y = p;
        SplitRank(ls(p), rk, x, ls(p));
        PushUp(y);
    } else {
        x = p;
        SplitRank(rs(p), rk - siz[ls(p)] - 1, rs(p), y);
        PushUp(x);
    }
}

int Merge(int x, int y) {
    if(!x || !y)
        return x | y;
    if(rnd[x] < rnd[y]) {
        rs(x) = Merge(rs(x), y);
        PushUp(x);
        return x;
    } else {
        ls(y) = Merge(x, ls(y));
        PushUp(y);
        return y;
    }
}

int NewNode(int v) {
    ++tot;
    ch[tot][0] = ch[tot][1] = 0;
    val[tot] = v, rnd[tot] = rand();
    siz[tot] = 1;
    return tot;
}

void Insert(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v, x, y);
    root = Merge(Merge(x, NewNode(v)), y);
}

void Remove(int &root, int v) {
    int x = 0, y = 0, z = 0;
    SplitValue(root, v, x, z);
    SplitValue(x, v - 1, x, y);
    y = Merge(ls(y), rs(y));
    root = Merge(Merge(x, y), z);
}

int GetRank(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v - 1, x, y);
    int rk = siz[x] + 1;
    root = Merge(x, y);
    return rk;
}

int GetValue(int &root, int rk) {
    int x = 0, y = 0, z = 0;
    SplitRank(root, rk, x, z);
    SplitRank(x, rk - 1, x, y);
    int v = val[y];
    root = Merge(Merge(x, y), z);
    return v;
}

int GetPrev(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v - 1, x, y);
    int prev = GetValue(x, siz[x]);
    root = Merge(x, y);
    return prev;
}

int GetNext(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v, x, y);
    int next = GetValue(y, 1);
    root = Merge(x, y);
    return next;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    scanf("%d", &n);
    Init();
    for(int i = 1; i <= n; ++i) {
        int op, x;
        scanf("%d%d", &op, &x);
        switch(op) {
            case 1:
                Insert(root, x);
                break;
            case 2:
                Remove(root, x);
                break;
            case 3:
                printf("%d\n", GetRank(root, x));
                break;
            case 4:
                printf("%d\n", GetValue(root, x));
                break;
            case 5:
                printf("%d\n", GetPrev(root, x));
                break;
            case 6:
                printf("%d\n", GetNext(root, x));
                break;
        }
    }
    return 0;
}

Treap的O(n)建树和回收:

//O(n)建树,返回新树的根
int st[MAXN], stop;
char buf[MAXN];
inline int Build(int n) {
    stop = 0;
    for(int i = 0; i < n; ++i) {
        int tmp = NewNode(buf[i]), last = 0;
        while(stop && rnd[st[stop]] > rnd[tmp]) {
            last = st[stop];
            PushUp(last);
            st[stop--] = 0;
        }
        if(stop)
            rs(st[stop]) = tmp;
        ls(tmp) = last;
        st[++stop] = tmp;
    }
    while(stop)
        PushUp(st[stop--]);
    return st[1];
}

//O(n)回收整棵树
inline void UnBuild(int p) {
    if(!p)
        return;
    UnBuild(ls(p));
    UnBuild(rs(p));
    RecBin.push(p);
}

非递归的不带修改的查询,方便可持久化:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls(p) ch[p][0]
#define rs(p) ch[p][1]

const int MAXN = 100000 + 5;
int val[MAXN], ch[MAXN][2], rnd[MAXN], siz[MAXN], tot, root;

void Init() {
    tot = root = 0;
}

void PushUp(int p) {
    siz[p] = siz[ls(p)] + siz[rs(p)] + 1;
}

void SplitValue(int p, int v, int &x, int &y) {
    if(!p) {
        x = y = 0;
        return;
    }
    if(v < val[p]) {
        y = p;
        SplitValue(ls(p), v, x, ls(p));
        PushUp(y);
    } else {
        x = p;
        SplitValue(rs(p), v, rs(p), y);
        PushUp(x);
    }
}

void SplitRank(int p, int rk, int &x, int &y) {
    if(!p) {
        x = y = 0;
        return;
    }
    if(rk <= siz[ls(p)]) {
        y = p;
        SplitRank(ls(p), rk, x, ls(p));
        PushUp(y);
    } else {
        x = p;
        SplitRank(rs(p), rk - siz[ls(p)] - 1, rs(p), y);
        PushUp(x);
    }
}

int Merge(int x, int y) {
    if(!x || !y)
        return x | y;
    if(rnd[x] < rnd[y]) {
        rs(x) = Merge(rs(x), y);
        PushUp(x);
        return x;
    } else {
        ls(y) = Merge(x, ls(y));
        PushUp(y);
        return y;
    }
}

int NewNode(int v) {
    ++tot;
    ch[tot][0] = ch[tot][1] = 0;
    val[tot] = v, rnd[tot] = rand();
    siz[tot] = 1;
    return tot;
}

void Insert(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v, x, y);
    root = Merge(Merge(x, NewNode(v)), y);
}

void Remove(int &root, int v) {
    int x = 0, y = 0, z = 0;
    SplitValue(root, v, x, z);
    SplitValue(x, v - 1, x, y);
    y = Merge(ls(y), rs(y));
    root = Merge(Merge(x, y), z);
}

int GetRank2(int p, int v) {
    int rk = 1;
    while(p) {
        if(v < val[p])
            p = ls(p);
        else if(v == val[p])
            p = ls(p);
        else {
            rk += siz[ls(p)] + 1;
            p = rs(p);
        }
    }
    return rk;
}

int GetValue2(int p, int rk) {
    while(p) {
        if(rk <= siz[ls(p)])
            p = ls(p);
        else if(rk == siz[ls(p)] + 1)
            return val[p];
        else {
            rk -= siz[ls(p)] + 1;
            p = rs(p);
        }
    }
}

int GetPrev2(int p, int v) {
    int prev;
    while(p) {
        if(v <= val[p])
            p = ls(p);
        else {
            prev = val[p];
            p = rs(p);
        }
    }
    return prev;
}

int GetNext2(int p, int v) {
    int next;
    while(p) {
        if(v < val[p]) {
            next = val[p];
            p = ls(p);
        } else
            p = rs(p);
    }
    return next;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    scanf("%d", &n);
    Init();
    for(int i = 1; i <= n; ++i) {
        int op, x;
        scanf("%d%d", &op, &x);
        switch(op) {
            case 1:
                Insert(root, x);
                break;
            case 2:
                Remove(root, x);
                break;
            case 3:
                printf("%d\n", GetRank2(root, x));
                break;
            case 4:
                printf("%d\n", GetValue2(root, x));
                break;
            case 5:
                printf("%d\n", GetPrev2(root, x));
                break;
            case 6:
                printf("%d\n", GetNext2(root, x));
                break;
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Inko/p/11516422.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/aoying6521/article/details/101785680

智能推荐

如何面试Java中级开发(16k)试题讲解和Java学习_如何面试中级开发-程序员宅基地

文章浏览阅读1.3k次。面试题:HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理Spring的AOP和IOC是什么?使用场景有哪些?Spring事务,事务的属性,传播行为,数据库隔离级别Spring和SpringMVC,MyBatis以及SpringBoot的注解分别有哪些?SpringMVC的工作原理,SpringBoot框架的优点,MyBatis框架的优点SpringCould组件有哪些,他们的作用是什么?(说七八个)微服务的CAP是什么?BASE是什么?_如何面试中级开发

Android Studio 代理问题总结(Gradle代理,模拟器代理)_andorid studio 模拟器走本地代理-程序员宅基地

文章浏览阅读1.3w次,点赞5次,收藏11次。Android Studio 的 代理 和 gradle的代理 和 AVD模拟器 代理_andorid studio 模拟器走本地代理

技术明星的毁灭----团队中的识人与用人-程序员宅基地

文章浏览阅读1.6k次。 他,是一个有15年开发经验的优秀软件工程师! 他,是我学习C++的老师! 他,可以解决公司里其他所有大侠们解决不了的技术难题! 他,是公司每一个技术人员值得学习的榜样! 他,从一个项目经理后来成为一家Nasdaq上市公司的技术总监! 他,后来负责这家公司一个分公司的管理,做了公

逆序输出字符串_输入一个字符串将其逆序输出-程序员宅基地

文章浏览阅读9.9k次,点赞7次,收藏33次。编写程序:先设计一个函数fun(char *s)把字符串中的内容逆置后,将字符串输出。例如:字符串中原有内容为:gfedcba,则调用该函数后,串中的内容为:abcdefg。思想:把字符串中的内容逆置,也就是调换位置,通过中间变量,把s[len-i-1]的内容和s[i]的内容调换位置,从而实现内容逆置的结果。下面展示一些 输入输出结果。_输入一个字符串将其逆序输出

js日期格式化yyyy-MM-dd_js 日期格式化为yyyy-mm-dd-程序员宅基地

文章浏览阅读4.6w次,点赞9次,收藏13次。function formatDate(date) {console.log(date);// date = new Date();date = new Date(Date.parse(date.replace(/-/g, "/"))); //转换成Data();console.log(date);var y = date.getFullYear();console.log(y);var m = date.getMonth() + 1;m = m < 10 ? '0' + m :..._js 日期格式化为yyyy-mm-dd

深入HQL学习以及HQL和SQL的区别_hql sql-程序员宅基地

文章浏览阅读5.8w次,点赞38次,收藏218次。HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:在查询语句中设定各种查询条件;支持投影查询, 即仅检索出对象的部分属性;支持分页查询;支持连接查询;支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字;提供内_hql sql

随便推点

mysql中net start mysql57出现服务无法启动显现-程序员宅基地

文章浏览阅读3.1k次,点赞3次,收藏4次。首先问题的出现有很多情况,如下只是针对我自己电脑发生的情况做总结,希望可以帮到有需要的小伙伴。我是刚接触mysql的小白,跟着康老师学的。因为mysql5的版本无法解析中文字符,每次添加中文数据都需要用到utf8,于是打算配置文件,让输入中文可以得到识别,不用每次都去打utf8。他第9节的时候配置了my.ini文件,如下结果就出现了net start mysql57出现服务无法启动显现的情形。后面我在用到net stop mysql57关闭服务后,打算用net start m..._net start mysql57

php中遍历数组_遍历PHP数组的6种方式-程序员宅基地

文章浏览阅读365次。在PHP的日常操作中,数组是最常出现的结构,而我们几乎每天都在处理数组相关的内容。那么问题来了,你一般怎么遍历并处理数组。1、foreach很熟悉吧,是不是你的最爱?$arr = ['a', 'b', 'c'];foreach ($arr as $key => $value) {$arr[$key] = $value . '_i';}print_r($arr); // ['a_i', 'b_..._php 数组元素遍历处理

webstorm 2019 最新注册码 破解方法(持续更新中~_webdriver 2019 license-程序员宅基地

文章浏览阅读1.7w次。webstorm 对咱们前端来说是无人不知无人不晓,那么下面就安利一下webstorm的注册方法吧。2019-2-21更新(注册码激活):访问http://idea.lanyus.com/按照箭头顺序操作即可。第一步,下载资源JetbrainsIdesCrack-4.2-release-enc.jar,第二步,修改文件,1.、2...._webdriver 2019 license

hive的使用及基本操作完整版_hive使用-程序员宅基地

文章浏览阅读8.8k次,点赞9次,收藏22次。安装mysql、hive步骤一、什么是hiveHive是基于Hadoop的一个数据仓库工具(离线),可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。操作接口采用类SQL语法,提供快速开发的能力, 避免了去写MapReduce,减少开发人员的学习成本, 功能扩展很方便。用于解决海量结构化日志的数据统计。本质是:将 HQL 转化成 MapReduce 程序1、优缺点优点:1) 操作接口采用类 SQL 语法,提供快速开发的能力(简单、容易上手)。 2) 避免了去写 MapR_hive使用

课堂笔记day1__基础_编写main方法,声明一个product对象数组products-程序员宅基地

文章浏览阅读540次。运算符的优先级:顺序运算符1括号 ()2一元运算符 ++、-- 和 !3算术运算符 +、-、*、/、%4关系运算符 >、>=、<、<=、==和 !=5逻辑运算符 &&(与) 、或者6条件运算符和赋值运算符 ? : 、=、*=、/=、+=、-=注意:顺序5的地方 或者(||)..._编写main方法,声明一个product对象数组products

关于CountDownLatch和CyclicBarrier的认识_关于cyclicbarrier和countdownlatch说法正确的是-程序员宅基地

文章浏览阅读917次。**关于CountDownLatch的认识** 今天在浏览论坛的时候发现了一个有趣的东西,自己之前没有用过,在此记录一下,一遍日后阅读浏览, 作为程序员,尤其使一个已近做了3年的java程序员来说,总感觉自己都会了,其实自己稍微看看又发现自己咋又不知道呢, 这个也是我的感慨,应为即将面临这找工作,自己还有有一点压力的,还是比较怕技术面试的,不知道面试官会问哪些奇怪的问题,这些问题又是我不知道的_关于cyclicbarrier和countdownlatch说法正确的是

推荐文章

热门文章

相关标签