两个一起学的,就放一块了。

主要是用来存板子。


Splay

//This is a Splay Tree.
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1e5+5,INF=0x3f3f3f3f;
int n,root,cntnode;
struct node //始终满足左小右大
{
int fa,ch[2],val,siz,cnt;
//int mark; //区间反转标记
}t[N];
inline bool get(int x) {return t[t[x].fa].ch[1]==x;} //右儿子?1:0
inline void upd(int x) {t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+t[x].cnt;} //更新计数
inline void zigzag(int x) //旋转操作
{
int fa=t[x].fa; int gfa=t[fa].fa;
int d1=get(x),d2=get(fa);
t[fa].ch[d1]=t[x].ch[d1^1]; t[t[x].ch[d1^1]].fa=fa; //断开fa与x,连接fa与x的儿子
t[gfa].ch[d2]=x; t[x].fa=gfa; //断开gfa与fa,连接gfa与x
t[fa].fa=x; t[x].ch[d1^1]=fa; //连接x与fa
upd(fa); upd(x); //一定是先upd fa再upd x,因为此时fa是x的节点
}
void splay(int x,int goal) //伸展操作,即将一个节点x不断旋转至goal的儿子的位置
{
while(t[x].fa!=goal)
{
int fa=t[x].fa; int gfa=t[fa].fa;
int d1=get(x),d2=get(fa);
if(gfa!=goal)
{
if(d1==d2) zigzag(fa); //双旋操作——如果x与fa处在同一方向,要先旋转fa
else zigzag(x);
}
zigzag(x);
}
if(goal==0) root=x; //这里用goal=0来实现把x变为根节点的操作
}
//以上为维持splayTree功能的基本操作,以下将实现splay的几种常见用途
void insert(int val) //插入值功能
{
int node=root,fa=0;
while(node && t[node].val!=val)
fa=node,node=t[node].ch[t[node].val<val]; //通过不断遍历树来找到插入位置
if(node) t[node].cnt++; //已有此编号
else
{
node=++cntnode; if(fa) t[fa].ch[t[fa].val<val]=node;
t[node].fa=fa; t[node].val=val; t[node].cnt=t[node].siz=1;
}
splay(node,0);
}
int kth(int k) //第k小的数
{
int node=root;
for(;;)
{
int son=t[node].ch[0];
if(k<=t[son].siz) node=son;
else if(k>t[son].siz+t[node].cnt)
k-=t[son].siz+t[node].cnt,
node=t[node].ch[1];
else return t[node].val;
}
}
int find(int val) //查找值
{
int node=root;
while(t[node].val!=val && t[node].ch[t[node].val<val])
node=t[node].ch[t[node].val<val];
return node;
}
int getrk(int val)
{
splay(find(val),0);
return t[t[root].ch[0]].siz;
}
int presuc(int val,int tp) //查找前驱后继,tp=0为前驱,tp=1为后继
{
splay(find(val),0); int node=root;
if(t[node].val<val&&!tp || t[node].val>val&&tp) //如果找到的节点满足要求就直接返回
return node;
node=t[node].ch[tp];
while(t[node].ch[tp^1])
node=t[node].ch[tp^1]; //否则找节点左/右子树中最靠右/左的节点(根据平衡树的性质
return node;
}
void delet(int val)
{
int pre=presuc(val,0),suc=presuc(val,1);
splay(pre,0); splay(suc,pre); //将pre旋转到根,suc旋转到pre的下面,那么suc的左子树就是要删除的
if(t[t[suc].ch[0]].cnt>1)
{
t[t[suc].ch[0]].cnt--; //常规的删除
splay(t[suc].ch[0],0);
}
else t[suc].ch[0]=0;
}
int main()
{
insert(-INF); insert(INF);
scanf("%d",&n);
for(int i=1,opt,x;i<=n;++i)
{
scanf("%d%d",&opt,&x);
if(opt==1) insert(x);
if(opt==2) delet(x);
if(opt==3) printf("%d\n",getrk(x));
if(opt==4) printf("%d\n",kth(x+1));
if(opt==5) printf("%d\n",t[presuc(x,0)].val);
if(opt==6) printf("%d\n",t[presuc(x,1)].val);
}
return 0;
}

FHQ-Treap

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std; const int N=100010;
int tot,root;
struct FHQtreap
{
int ch[2],val,pri,siz;
#define l(x) t[x].ch[0]
#define r(x) t[x].ch[1]
}t[N]; inline void upd(int x) {t[x].siz=t[l(x)].siz+t[r(x)].siz+1;}
inline int newNode(int x)
{
t[++tot].siz=1,t[tot].val=x,t[tot].pri=rand();
return tot;
} int merge(int x,int y)
{
if(!x||!y) return x|y;
if(t[x].pri<t[y].pri) return r(x)=merge(r(x),y),upd(x),x;
else return l(y)=merge(x,l(y)),upd(y),y;
} void split(int now,int k,int &x,int &y)
{
if(!now) {x=y=0; return;}
if(t[now].val<=k) x=now,split(r(now),k,r(now),y);
else y=now,split(l(now),k,x,l(now));
upd(now);
} int kth(int now,int k)
{
while(1)
if(k<=t[l(now)].siz) now=l(now);
else
{
if(k==t[l(now)].siz+1) return now;
else k-=t[l(now)].siz+1,now=r(now);
}
} int main()
{
srand(19260817);
int T; scanf("%d",&T);
while(T--)
{
int opt,a,x,y,z;
scanf("%d%d",&opt,&a);
if(opt==1)
{
split(root,a,x,y);
root=merge(merge(x,newNode(a)),y);
}
if(opt==2)
{
split(root,a,x,z);
split(x,a-1,x,y);
y=merge(l(y),r(y));
root=merge(merge(x,y),z);
}
if(opt==3)
{
split(root,a-1,x,y);
printf("%d\n",t[x].siz+1);
root=merge(x,y);
}
if(opt==4) printf("%d\n",t[kth(root,a)].val);
if(opt==5)
{
split(root,a-1,x,y);
printf("%d\n",t[kth(x,t[x].siz)].val);
root=merge(x,y);
}
if(opt==6)
{
split(root,a,x,y);
printf("%d\n",t[kth(y,1)].val);
root=merge(x,y);
}
}
return 0;
}

Splay与FHQ-Treap的更多相关文章

  1. 【数据结构】平衡树splay和fhq—treap

    1.BST二叉搜索树 顾名思义,它是一棵二叉树. 它满足一个性质:每一个节点的权值大于它的左儿子,小于它的右儿子. 当然不只上面那两种树的结构. 那么根据性质,可以得到该节点左子树里的所有值都比它小, ...

  2. NOI 2002 营业额统计 (splay or fhq treap)

    Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每 ...

  3. Luogu P3391 文艺平衡树(Splay or FHQ Treap)

    这道题要求区间反转...好东西.. 对于Splay:把l-1旋到根,把r+1旋到根的右儿子,这样r+1的左儿子就是整个区间了,然后对这个区间打个tg 注意要插-Inf和Inf到树里面,防止越界,坐标要 ...

  4. 平衡树合集(Treap,Splay,替罪羊,FHQ Treap)

    今天翻了翻其他大佬的博客,发现自己有些...颓废... 有必要洗心革面,好好学习 序:正常的BST有可能退化,成为链,大大降低效率,所以有很多方法来保持左右size的平衡,本文将简单介绍Treap,S ...

  5. 平衡树(Splay、fhq Treap)

    Splay Splay(伸展树)是一种二叉搜索树. 其复杂度为均摊\(O(n\log n)\),所以并不可以可持久化. Splay的核心操作有两个:rotate和splay. pushup: 上传信息 ...

  6. 在平衡树的海洋中畅游(四)——FHQ Treap

    Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...

  7. BZOJ3159: 决战(FHQ Treap)

    传送门: 解题思路: 算是补坑了,这题除了Invert以外就可以树剖线段树解决了. 考虑Invert操作,延续先前树链剖分的做法,考虑先前算法的瓶颈. 最暴力的方法是暴力交换权值,然而这种方法忽略了当 ...

  8. 「FHQ Treap」学习笔记

    话说天下大事,就像fhq treap —— 分久必合,合久必分 简单讲一讲.非旋treap主要依靠分裂和合并来实现操作.(递归,不维护fa不维护cnt) 合并的前提是两棵树的权值满足一边的最大的比另一 ...

  9. FHQ Treap摘要

    原理 以随机数维护平衡,使树高期望为logn级别 不依靠旋转,只有两个核心操作merge(合并)和split(拆分) 因此可持久化 先介绍变量 ; int n; struct Node { int v ...

  10. FHQ Treap小结(神级数据结构!)

    首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...

随机推荐

  1. 利用 Bean Validation 来简化接口请求参数校验

    团队新来了个校招实习生静静,相互交流后发现竟然是我母校同实验室的小学妹,小学妹很热情地认下了我这个失散多年的大湿哥,后来... 小学妹:大湿哥,咱们项目里的 Controller 怎么都看不到参数校验 ...

  2. PTA7~9题目集总结与归纳

    前言: 总结三次题目集的知识点.题量.难度等情况. 目录: 题目集7(7-1).(7-2)两道题目的递进式设计分析总结 题目集8和题目集9两道ATM机仿真题目的设计思路分析总结 一. 题目集7(7-1 ...

  3. Nexus 安装配置教程

    目录 为什么使用 Nexus Docker 模式安装 Nexus 使用 data volume 使用本地目录 Nexus 配置 配置 Blob Stores Nexus 使用 包下载 包上传 参考 为 ...

  4. 2020想进大厂你不得不了解的MySQL意外事件的查询技巧

    导读:数据库是导致应用系统运行缓慢的常见原因.面对数据库引性能问题,很多开发者或者DBA却束手无策.本文作者经过多年的实际经验,整理了一些材料,将Linux环境下MySQL性能突发事件问题排查技巧分享 ...

  5. 使用 vite 构建一个表情选择插件

    初始化 Vite 基于原生 ES 模块提供了丰富的内建功能,开箱即用.同时,插件足够简单,它不需要任何运行时依赖,只需要安装 vite (用于开发与构建)和 sass (用于开发环境编译 .scss ...

  6. 2021Qt打包发布教程

    因为最近写了一个程序,然后想着能给室友玩耍,就研究了一下如何打包,写这篇博客记录一下 1. 首先获得程序的Release版本 就是点击这个Release,然后构建一遍 2. 进入构建的release文 ...

  7. 详解 CDN 加速

    背景 本来是为了深入了解 CDN 的,结果发现前置知识:IP.域名.DNS 都还不算特别熟,所以先写了他们 现在终于来聊一聊 CDN 啦 本文素材均出自:https://www.bilibili.co ...

  8. 24、mysql数据库优化

    24.1.如何判断网站慢的排查顺序: 客户端->web->nfs->数据库: 24.2.uptime命令详解: [root@backup ~]#uptime 13:03:23 up ...

  9. 「一本通 3.1 练习 4」Tree 题解

    题目描述 原题来自:2012 年国家集训队互测 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有 条白色边的生成树.题目保证有解. 输入格式 第一行V,E,need 分别表示点数, ...

  10. 利用C语言判别用户输入数的奇偶性和正负性

    要求:利用C语言判别用户输入数的奇偶性和正负性 提示:可以利用%求余数来判别 由题可知 我们需要if..else的结构来实现区分奇偶和正负 区分奇偶我们可以用: if (a % 2 == 0) { p ...