treap = tree + heap 树堆(treap:让BST尽量随机)

动态维护一个有序序列

对于一个大根堆:
最大值:一直往右走
最小值:一直往左走

treap实现操作 set实现
①插入 insert
②删除(使其变成叶子节点) erase
③找前驱(中序遍历的前一个位置)/后继(中序遍历的后一个位置) lower_bound
④找最大/最小 begin(),end();
⑤求某个值的排名
⑥求排名是k的数是谁
⑦比某个数小的最大值 ( 这个数可以不存在 )
⑧比某个数大的最小值

平衡树一个点对应一个数,一共n个数,空间复杂度为O(n)O(n)O(n)

左旋/右旋后中序遍历完全不变(左中右)

    x      右旋       y/ \     zig      / \y   b    --->    a   x/ \       <---       / \
a   z      zag       z   b左旋

P3369 【模板】普通平衡树

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>using namespace std;const int N = 100010, INF = 1e8 + 7;int n, m;struct node{int l, r;//左右儿子int key;//真正的权值int val;//随机的平衡因子int cnt;//相同的数有多少个int size;//整棵树的结点个数
}tr[N];int root, idx;void pushup(int p){tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + tr[p].cnt;
}int get_node(int key){tr[ ++ idx].key = key;tr[idx].val = rand();//!堆所维护的val是随机值,为了让树变得更随机以增加搜索树效率tr[idx].cnt = tr[idx].size = 1;return idx;
}/*!往左递归时左儿子val大于根节点val就右旋*/
/*!往右递归时右儿子val大于根节点val就左旋*/
/*      x    右旋         y/ \   zig        / \y   b  --->      a   x/ \     <---         / \a   z    zag         z   b左旋              */void zig(int &p){//右旋int q = tr[p].l;tr[p].l = tr[q].r;tr[q].r = p, p = q;pushup(tr[p].r), pushup(p);
}void zag(int &p){//左旋int q = tr[p].r;tr[p].r = tr[q].l;tr[q].l = p, p = q;pushup(tr[p].l), pushup(p);
}void build(){get_node(-INF), get_node(INF);//两个哨兵边界root = 1;//-INFtr[root].r = 2;//INFpushup(root);if(tr[1].val < tr[2].val)zag(root);//因为val是随机的,所以要判断右儿子(因为当前只有两个点,只有root右儿子)//如果右儿子随机到的val大于root就左旋
}/*operator 1 : 插入一个数*/void insert(int &p, int key){if(!p) p = get_node(key);//如果树中没有这个就新建一个结点else if(tr[p].key == key) tr[p].cnt ++ ;else if(tr[p].key > key){//大就在左边insert(tr[p].l, key);if(tr[tr[p].l].val > tr[p].val)zig(p);}else { // 否则就在右边insert(tr[p].r, key);if(tr[tr[p].r].val > tr[p].val)zag(p);}pushup(p);
}/*operator 2 : 删除一个数*/void remove(int &p, int key){//删除操作:每次旋转都会使得它的深度+1,一直旋转到叶子节点,然后删除if(!p) return ;if(tr[p].key == key){//找到了if(tr[p].cnt > 1) tr[p].cnt -- ;else if(tr[p].l || tr[p].r){//!右旋往右走if(!tr[p].r || tr[tr[p].l].val > tr[tr[p].r].val){//如果没有右子树,右旋一次就到叶子节点了。或者说左子树随机到的val > 右子树随机到的val,那么必须右旋zig(p);remove(tr[p].r, key);}//!左旋往左走else {zag(p);remove(tr[p].l, key);}}else p = 0;//如果到了叶子节点就直接删掉}else if(tr[p].key > key) remove(tr[p].l, key);//往左边找else remove(tr[p].r, key);//往右边找pushup(p);//每次别忘了pushup,因为本题中维护了一个size
}//下面的几个函数只是查询不需要修改,所以不用写&p/*operator 3 : 通过数值找排名 */int get_rank_by_key(int p, int key){if(!p) return 0;//如果找到了,返回左子树个数 + 自己(这里不是cnt因为根据题意,要找的排名如果相同就找最左边的,最小的)if(tr[p].key == key) return tr[tr[p].l].size + 1;if(tr[p].key > key)return get_rank_by_key(tr[p].l, key);return tr[tr[p].l].size + tr[p].cnt + get_rank_by_key(tr[p].r, key);
}/*operator 4 : 通过排名找数值 */int get_key_by_rank(int p, int rank){if(!p) return INF;if(tr[tr[p].l].size >= rank) return get_key_by_rank(tr[p].l, rank);if(tr[tr[p].l].size + tr[p].cnt >= rank)//左边少加上中间的却大于rank,说明就在中间return tr[p].key;return get_key_by_rank(tr[p].r, rank - tr[tr[p].l].size - tr[p].cnt);//注意递归到右边时rank要减去左边的
}/*operator 5 : 找到严格小于key的最大数(前驱) */int get_prev(int p, int key){if(!p) return -INF;//!左边if(tr[p].key >= key) return get_prev(tr[p].l, key);//右边和中间return max(tr[p].key, get_prev(tr[p].r, key));
}/*operator 6 : 找到严格大于key的最小数(后继) */int get_next(int p, int key){if(!p) return INF;//!右边if(tr[p].key <= key) return get_next(tr[p].r, key);//左边和中间return min(tr[p].key, get_next(tr[p].l, key));
}int main(){build();scanf("%d", &n);while(n -- ){int op, x;scanf("%d%d", &op, &x);if(op == 1)insert(root, x);else if(op == 2)remove(root, x);else if(op == 3)printf("%d\n", get_rank_by_key(root, x) - 1);//因为最前面有一个自己设的哨兵,所以得到的rank比真实的rank大1else if(op == 4)printf("%d\n", get_key_by_rank(root, x + 1));//根据rank找key,前面有一个哨兵,所以rank要从真实的rank+1变成树里的rankelse if(op == 5)printf("%d\n", get_prev(root, x));else printf("%d\n", get_next(root, x));}return 0;
}

【数据结构】平衡树 - treap相关推荐

  1. 平衡树-Treap基础内容

    平衡树-Treap 2021年8月6日 什么是平衡树? 平衡树是指任意节点左右子树高度差都小于等于1的二叉树. 平衡树干什么? 平衡树对序列的排序,寻找元素的位置有很方便的操作 算法原理 建树 Tre ...

  2. 信息学奥赛一本通 提高篇 第6章 平衡树Treap

    随笔分类 - 动态规划--树形动态规划 动态规划--树形动态规划 - 随笔分类 - 符拉迪沃斯托克 - 博客园 平衡树 Treap 平衡树_百度百科 平衡树--treap - genius777 - ...

  3. 数据结构之平衡树(Treap)

    平衡树是二叉搜索树和堆合并构成的新数据结构,所以它的名字取了Tree和Heap各一半,叫做Treap. 堆和树的性质是冲突的,二叉搜索树满足左子树<根节点<右子树,而堆是满足根节点小于等于 ...

  4. BZOJ 3224: Tyvj 1728 普通平衡树 treap

    3224: Tyvj 1728 普通平衡树 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...

  5. BZOJ 3224 普通平衡树 treap or vector

    很明显这是一道treap的题,但看了黄学长的博客后,也让我大开了眼界,没想到vector也能用那么短的编码量把这道题AC,着实令我敬佩.这也提醒了我 STL 的重要性. 的确, 对于C++ 选手来说, ...

  6. 2019 ICPC 南昌 K. Tree(树上启发式合并,平衡树 treap)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://nanti.jisuanke.com/t/42586 Problem 给定一 ...

  7. 数据结构之Treap

    1. 概述 同splay tree一样,treap也是一个平衡二叉树,不过Treap会记录一个额外的数据,即优先级.Treap在以关键码构成二叉搜索树的同时,还按优先级来满足堆的性质.因而,Treap ...

  8. 【BZOJ4370】【IOI2015】horses 数据结构 平衡树+线段树

    4370: [IOI2015]horses马 Time Limit: 30 Sec Memory Limit: 1500 MB Description 像他的祖先一样,Mansur喜欢繁殖马匹.目前, ...

  9. 平衡树 - treap

    整理的算法模板合集: ACM模板 operator 1 : 插入一个数 operator 2 : 删除一个数 operator 3 : 通过数值找排名 operator 4 : 通过排名找数值 ope ...

最新文章

  1. 扩增子分析解读4去嵌合体,非细菌序列,生成代表性序列和OTU表
  2. 一个 NAND flash写函数
  3. 适合打游戏的计算机内存品牌型号,玩游戏电脑内存要多大合适?不同内存容量玩游戏区别实测...
  4. java stringbuffer倒置_Java程序设计05——String和StringBuffer
  5. 如何使用W5300实现ADSL连接(二)
  6. Gnosis发起提案就是否推出Gnosis协议v2版本展开讨论
  7. 支持Flash和JavaScript的图表控件FusionWidgets
  8. ubuntu 下 apache2 查看 已加载的模块 命令
  9. 2022年最新全国各省五级行政区划代码(省/市/区县/乡镇/村)
  10. JAVA 实现《中国象棋》游戏
  11. 苹果appstore中兑换码的使用方法
  12. 水果店的货源来自哪里,怎样做水果店找货源
  13. 天宝营养冲刺深交所:年营收12.5亿 拟募资7亿
  14. 计算机网络笔试面试常考
  15. 我,35岁程序员,离职前是这么做的
  16. C#中在鼠标经过Button控件时显示提示信息(弹出气泡提示框)
  17. 笔迹鉴定流程,都需要什么,费用多少?
  18. java 视频处理 ffmped+mencoder
  19. 电脑分屏显示设置【转】
  20. C语言谭浩强第5版章节编程题

热门文章

  1. 在计算机视觉方向如何快速提升自己?
  2. 第十九篇:主题建模Topic Modelling
  3. 定义一个DSL风格的LifecycleObserver(Kotlin)
  4. 架构师升级之路,你掌握了吗?
  5. Spring security获取当前用户
  6. 报错——StackOverflowError
  7. Autolayout学习(1)-了解Autoreszing
  8. 华中科技大学计算机通信与网络实验,华中科技大学计算机通信与网络实验报告Socket编程实验.docx...
  9. 简述数学建模的过程_数学建模研究过程指导:从高中数学体会数学概貌和数学建模...
  10. php 偷偷转移别人权重,判断百度蜘蛛偷偷进行301转移权重 给新站提权