该模板题的题目链接


很多人看到了FHQ Treap都不知道它是干什么用的,今天也是刚学的FHQ Treap,学了一整天了,终于过掉了洛谷的P3369了,也算是对这个算法有了些自己的了解,还是错的太多次,不然谁debug找到都快搞明白什么是FHQ Treap。

很多人都知道splay的平衡树、还有treap平衡树。但是普通的treap需要进行不断的反转,代码量着实有些大了,而且,优化的FHQ Treap还可以做到可持久化,所以,我就学习了FHQ Treap。

FHQ Treap只有:(一)、分离(split)(二)、合并(merge)的功能「在这里由于merge函数名冲突,我利用mix()代替」。

讲一下FHQ Treap在本题中的几个应用:

  1. 插入x数
  2. 删除x数(若有多个相同的数,因只删除一个)
  3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
  4. 查询排名为x的数
  5. 求x的前驱(前驱定义为小于x,且最大的数)
  6. 求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的讲解】【随机数、各数组、函数运用】相关推荐

  1. fhq treap ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

    二次联通门 : LibreOJ #104. 普通平衡树 #include <cstdio> #include <iostream> #include <algorithm ...

  2. FHQ Treap 详解

    0. 简单介绍 FHQ Treap,以下简写为fhq,是一种treap(树堆)的变体,功能比treap强大,代码比splay好写,易于理解,常数稍大. fhq不需要通过一般平衡树的左右旋转来保持平衡, ...

  3. Treap + FHQ Treap

    一:Treap 支持:插入.删除.查询 x x x 的排名.查询排名为 x x x 的数.查前驱.查后继.左旋右旋 模板题:P3369 [模板]普通平衡树 #include<bits/stdc+ ...

  4. 平衡树学习笔记之 fhq Treap

    平衡树学习笔记 1:fhq Treap(非旋 Treap) 正文开始前首先 %%% fhq 大佬. 众所周知,平衡树是一种 非常猥琐 码量堪忧的数据结构. 他的祖先是一种叫做二叉搜索树 ( B S T ...

  5. FHQ Treap及其可持久化与朝鲜树式重构

    FHQ Treap,又称无旋treap,一种不基于旋转机制的平衡树,可支持所有有旋treap.splay等能支持的操作(只有在LCT中会比splay复杂度多一个log).最重要的是,它是OI中唯一一种 ...

  6. P2596 [ZJOI2006]书架(fhq treap)

    P2596 [ZJOI2006]书架 我们用fhq treap来完成这一题 对于一个新插入的节点我们取权值为其索引值,其所记录的valuevaluevalue是其当前索引所在位置. 操作一:把索引为v ...

  7. 可持久化平衡树(FHQ Treap)

    两个最基本的操作 merge合并 split分割 merge 把两棵treap合并成一棵treap,要满足T1最大值要比T2最小值小,比较将随机数值key值更大的作为合并后的根 假设T1作为根节点作为 ...

  8. FHQ Treap 总结

    [前言(一堆废话)] 目前 OI 竞赛中两大主流平衡树之一就是 FHQ Treap(另一个是 Splay). 普通 BST 的中序遍历中,val 值构成一个单调递增的序列. Treap 在 BST 的 ...

  9. 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 ...

最新文章

  1. 深入解析Linux中的fork函数
  2. java和python的比较-java 和 python的一些对比
  3. Orac and Medians CodeForces - 1350D(思维)
  4. wxWidgets之wxGrid控件
  5. kafka处理流式数据_通过Apache Kafka集成流式传输大数据
  6. python Web抓取(一)[没写完]
  7. python制作u盘病毒_十行代码--用Python写一个USB病毒!
  8. 中西造园水法浅比【ZZ】
  9. 矩池云上加速下载GitHub文件办法
  10. 阶段3 2.Spring_06.Spring的新注解_7 spring整合junit问题分析
  11. (二十)STM32——电容触摸按键?建议改名为卫生纸按键
  12. ArrayList源码深度解析以及快速失败和安全失败机制详解【一万字】
  13. 计算机程序图标在哪,我的文档不见了 我的文档路径在哪 找回图标方法_电脑软硬件应用网_做中国最专业的计算机应用解决技术网站...
  14. 一篇文章,读懂品牌广告与效果广告的相同和不同
  15. 我陪你慢慢成长——苏子语录2015下半…
  16. 沃森计算机显能耐,微型气象预报有戏
  17. NR5G基础概念扫盲
  18. ssm+layui 超市管理系统 大学期末作业详解(1)
  19. jquery触发键盘按下事件
  20. Java一年两年工作经验面试题

热门文章

  1. 树莓派(USB麦克风和麦克风阵列) 录音和播放
  2. Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十六(商品排序,Thymeleaf快速入门,商品详情页的展示)
  3. groovy快速上手第2篇:数据类型篇
  4. CCS_3.3.83.20的安装步骤
  5. java int类型能表示的数值范围
  6. 名词解释:swagger, openapi, springfox, springdoc
  7. 内存拷贝函数 void * memcpy ()
  8. ServiceMesh到底好不好
  9. 易语言大漠对雷电模拟器中控后台的绑定
  10. HashSet和HashMap