FHQ Treap【基于P3369的讲解】【随机数、各数组、函数运用】
该模板题的题目链接
很多人看到了FHQ Treap都不知道它是干什么用的,今天也是刚学的FHQ Treap,学了一整天了,终于过掉了洛谷的P3369了,也算是对这个算法有了些自己的了解,还是错的太多次,不然谁debug找到都快搞明白什么是FHQ Treap。
很多人都知道splay的平衡树、还有treap平衡树。但是普通的treap需要进行不断的反转,代码量着实有些大了,而且,优化的FHQ Treap还可以做到可持久化,所以,我就学习了FHQ Treap。
FHQ Treap只有:(一)、分离(split);(二)、合并(merge)的功能「在这里由于merge函数名冲突,我利用mix()代替」。
讲一下FHQ Treap在本题中的几个应用:
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个)
- 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
那么应该怎么做这个?
先讲一下关于分离、合并函数:
分离函数split:
void split(int now, int k, int &x, int &y)
{if(!now) x = y = 0;else{if(val[now] <= k){x = now;split(rson[now], k, rson[now], y);}else{y = now;split(lson[now], k, x, lson[now]);}pushup(now);}
}
对于分离函数,我们要做到的就是找到那一半"<=K"的树,与">K"的那部分分开,分成两棵树。然后x得到的是小的那棵树,y得到大的那棵树。
合并函数merge(mix):
int mix(int x, int y)
{if(!x || !y) return x + y;if(pri[x] < pri[y]){rson[x] = mix(rson[x], y);pushup(x);return x;}else{lson[y] = mix(x, lson[y]);pushup(y);return y;}
}
合并两棵不同的树。
除去这两个,还有个迭代的就是求第K关系来用的:
int kth(int now, int k)
{while(true){if(k <= siz[lson[now]]) now = lson[now];else if(k == siz[lson[now]] + 1) return now;else { k -= ( siz[lson[now]] + 1 ); now = rson[now]; }}
}
求now根下的第K小的点的位置的值。
接下来,就是求题目中的要求的问题了:
1.插入x数
split(root, e1, x, y);root = mix(mix(x, new_node(e1)), y);
想要插入一个大小为X的数,有不能更改它的二叉查找树的性质lson<now<rson的性质,我们就要以X的大小为判断要求,"<=e1"的那串数弄出来,然后再把另一头的树弄出来,然后再合并三棵子树。
2.删除x数(若有多个相同的数,因只删除一个)
split(root, e1, x, z);split(x, e1-1, x, y);y = mix(lson[y], rson[y]);root = mix(mix(x, y), z);
删除一个值为X的数,由多个的话,仅删除一个,那么,不就是拆成3棵树,左边的树是"<x"的树,右边的是">x"的树,中间的树就是"==x"的树了,然后取它的头删除掉即可。
3.查询x数的排名(排名定义为比当前数小的数的个数+1+1。若有多个相同的数,因输出最小的排名)
split(root, e1-1, x, y);printf("%d\n", siz[x] + 1);root = mix(x, y);
想要查询X数的排名,无非就是找到"<X"的数的集合,然后"+1"即可。
4.查询排名为x的数
printf("%d\n", val[kth(root, e1)]);
找排名为X的数,就是要递归进去寻找了,然后后面有对应的函数。
5.求x的前驱(前驱定义为小于x,且最大的数)
split(root, e1-1, x, y);printf("%d\n", val[kth(x, siz[x])]);root = mix(x, y);
找到<x且最大的数,那么就是去"<x"的树里,找到树的最大值即可。
6.求x的后继(后继定义为大于x,且最小的数)
split(root, e1, x, y);printf("%d\n", val[kth(y, 1)]);root = mix(x, y);
类似与求前继的过程。
然后,今天先上一下具体的代码,明天继续修改,已经修改完成…… 请各大佬视察。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cstdlib>
#include <ctime>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, op, lson[maxN], rson[maxN], val[maxN], pri[maxN], siz[maxN], sz;
inline void pushup(int x) { siz[x] = siz[lson[x]] + siz[rson[x]] + 1; }
int new_node(int v)
{siz[++sz] = 1;val[sz] = v;pri[sz] = rand();return sz;
}
int mix(int x, int y)
{if(!x || !y) return x + y;if(pri[x] < pri[y]){rson[x] = mix(rson[x], y);pushup(x);return x;}else{lson[y] = mix(x, lson[y]);pushup(y);return y;}
}
void split(int now, int k, int &x, int &y)
{if(!now) x = y = 0;else{if(val[now] <= k){x = now;split(rson[now], k, rson[now], y);}else{y = now;split(lson[now], k, x, lson[now]);}pushup(now);}
}
int kth(int now, int k)
{while(true){if(k <= siz[lson[now]]) now = lson[now];else if(k == siz[lson[now]] + 1) return now;else { k -= ( siz[lson[now]] + 1 ); now = rson[now]; }}
}
int main()
{srand((unsigned)time(NULL));scanf("%d", &N);sz = 0;int root = 0, x, y, z;memset(lson, 0, sizeof(lson));memset(rson, 0, sizeof(rson));while(N--){scanf("%d", &op);int e1; scanf("%d", &e1);if(op == 1){split(root, e1, x, y);root = mix(mix(x, new_node(e1)), y);}else if(op == 2){split(root, e1, x, z);split(x, e1-1, x, y);y = mix(lson[y], rson[y]);root = mix(mix(x, y), z);}else if(op == 3){split(root, e1-1, x, y);printf("%d\n", siz[x] + 1);root = mix(x, y);}else if(op == 4){printf("%d\n", val[kth(root, e1)]);}else if(op == 5){split(root, e1-1, x, y);printf("%d\n", val[kth(x, siz[x])]);root = mix(x, y);}else{split(root, e1, x, y);printf("%d\n", val[kth(y, 1)]);root = mix(x, y);}}return 0;
}
/*
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598ans:10646584185492737
*/
FHQ Treap【基于P3369的讲解】【随机数、各数组、函数运用】相关推荐
- fhq treap ------ luogu P3369 【模板】普通平衡树(Treap/SBT)
二次联通门 : LibreOJ #104. 普通平衡树 #include <cstdio> #include <iostream> #include <algorithm ...
- FHQ Treap 详解
0. 简单介绍 FHQ Treap,以下简写为fhq,是一种treap(树堆)的变体,功能比treap强大,代码比splay好写,易于理解,常数稍大. fhq不需要通过一般平衡树的左右旋转来保持平衡, ...
- Treap + FHQ Treap
一:Treap 支持:插入.删除.查询 x x x 的排名.查询排名为 x x x 的数.查前驱.查后继.左旋右旋 模板题:P3369 [模板]普通平衡树 #include<bits/stdc+ ...
- 平衡树学习笔记之 fhq Treap
平衡树学习笔记 1:fhq Treap(非旋 Treap) 正文开始前首先 %%% fhq 大佬. 众所周知,平衡树是一种 非常猥琐 码量堪忧的数据结构. 他的祖先是一种叫做二叉搜索树 ( B S T ...
- FHQ Treap及其可持久化与朝鲜树式重构
FHQ Treap,又称无旋treap,一种不基于旋转机制的平衡树,可支持所有有旋treap.splay等能支持的操作(只有在LCT中会比splay复杂度多一个log).最重要的是,它是OI中唯一一种 ...
- P2596 [ZJOI2006]书架(fhq treap)
P2596 [ZJOI2006]书架 我们用fhq treap来完成这一题 对于一个新插入的节点我们取权值为其索引值,其所记录的valuevaluevalue是其当前索引所在位置. 操作一:把索引为v ...
- 可持久化平衡树(FHQ Treap)
两个最基本的操作 merge合并 split分割 merge 把两棵treap合并成一棵treap,要满足T1最大值要比T2最小值小,比较将随机数值key值更大的作为合并后的根 假设T1作为根节点作为 ...
- FHQ Treap 总结
[前言(一堆废话)] 目前 OI 竞赛中两大主流平衡树之一就是 FHQ Treap(另一个是 Splay). 普通 BST 的中序遍历中,val 值构成一个单调递增的序列. Treap 在 BST 的 ...
- FHQ TREAP 学习总结
F H Q T R E A P FHQ \ TREAP FHQ TREAP P r e p a r e K n o w l e d g e Prepare \ Knowledge Prepare Kn ...
最新文章
- 深入解析Linux中的fork函数
- java和python的比较-java 和 python的一些对比
- Orac and Medians CodeForces - 1350D(思维)
- wxWidgets之wxGrid控件
- kafka处理流式数据_通过Apache Kafka集成流式传输大数据
- python Web抓取(一)[没写完]
- python制作u盘病毒_十行代码--用Python写一个USB病毒!
- 中西造园水法浅比【ZZ】
- 矩池云上加速下载GitHub文件办法
- 阶段3 2.Spring_06.Spring的新注解_7 spring整合junit问题分析
- (二十)STM32——电容触摸按键?建议改名为卫生纸按键
- ArrayList源码深度解析以及快速失败和安全失败机制详解【一万字】
- 计算机程序图标在哪,我的文档不见了 我的文档路径在哪 找回图标方法_电脑软硬件应用网_做中国最专业的计算机应用解决技术网站...
- 一篇文章,读懂品牌广告与效果广告的相同和不同
- 我陪你慢慢成长——苏子语录2015下半…
- 沃森计算机显能耐,微型气象预报有戏
- NR5G基础概念扫盲
- ssm+layui 超市管理系统 大学期末作业详解(1)
- jquery触发键盘按下事件
- Java一年两年工作经验面试题
热门文章
- 树莓派(USB麦克风和麦克风阵列) 录音和播放
- Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十六(商品排序,Thymeleaf快速入门,商品详情页的展示)
- groovy快速上手第2篇:数据类型篇
- CCS_3.3.83.20的安装步骤
- java int类型能表示的数值范围
- 名词解释:swagger, openapi, springfox, springdoc
- 内存拷贝函数 void * memcpy ()
- ServiceMesh到底好不好
- 易语言大漠对雷电模拟器中控后台的绑定
- HashSet和HashMap