Splay与FHQ-Treap
两个一起学的,就放一块了。
主要是用来存板子。
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的更多相关文章
- 【数据结构】平衡树splay和fhq—treap
1.BST二叉搜索树 顾名思义,它是一棵二叉树. 它满足一个性质:每一个节点的权值大于它的左儿子,小于它的右儿子. 当然不只上面那两种树的结构. 那么根据性质,可以得到该节点左子树里的所有值都比它小, ...
- NOI 2002 营业额统计 (splay or fhq treap)
Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每 ...
- Luogu P3391 文艺平衡树(Splay or FHQ Treap)
这道题要求区间反转...好东西.. 对于Splay:把l-1旋到根,把r+1旋到根的右儿子,这样r+1的左儿子就是整个区间了,然后对这个区间打个tg 注意要插-Inf和Inf到树里面,防止越界,坐标要 ...
- 平衡树合集(Treap,Splay,替罪羊,FHQ Treap)
今天翻了翻其他大佬的博客,发现自己有些...颓废... 有必要洗心革面,好好学习 序:正常的BST有可能退化,成为链,大大降低效率,所以有很多方法来保持左右size的平衡,本文将简单介绍Treap,S ...
- 平衡树(Splay、fhq Treap)
Splay Splay(伸展树)是一种二叉搜索树. 其复杂度为均摊\(O(n\log n)\),所以并不可以可持久化. Splay的核心操作有两个:rotate和splay. pushup: 上传信息 ...
- 在平衡树的海洋中畅游(四)——FHQ Treap
Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...
- BZOJ3159: 决战(FHQ Treap)
传送门: 解题思路: 算是补坑了,这题除了Invert以外就可以树剖线段树解决了. 考虑Invert操作,延续先前树链剖分的做法,考虑先前算法的瓶颈. 最暴力的方法是暴力交换权值,然而这种方法忽略了当 ...
- 「FHQ Treap」学习笔记
话说天下大事,就像fhq treap —— 分久必合,合久必分 简单讲一讲.非旋treap主要依靠分裂和合并来实现操作.(递归,不维护fa不维护cnt) 合并的前提是两棵树的权值满足一边的最大的比另一 ...
- FHQ Treap摘要
原理 以随机数维护平衡,使树高期望为logn级别 不依靠旋转,只有两个核心操作merge(合并)和split(拆分) 因此可持久化 先介绍变量 ; int n; struct Node { int v ...
- FHQ Treap小结(神级数据结构!)
首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...
随机推荐
- Android系统编程入门系列之应用环境及开发环境介绍
作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...
- Linux学习笔记:Linux命令之文件处理命令
文件处理命令 touch 命令名称:touch 执行权限:所有用户 功能描述:创建空文件 语法:touch [文件名] touch创建文件的时候命名不推荐存在空格,如下面的情况 1touch prog ...
- 【NX二次开发】指定矢量控件,记住上次选择的方向
block UI控件如果有RetainValue属性,就用这个属性.没有这个属性可以参考下面这种方法.以矢量控件为例: 1.在apply_cb回调中,将控件值保存到文本中 double TopForT ...
- TensorFlow入门实操课程第一章教程笔记
神经元网络深度学习的起步程序 Hello World 第一个应用程序总是应该从超级简单的东西开始,这样可以看到代码如何产生和运作的整体框架. 就创建神经网络而言,我喜欢使用的例子是一个能够学习两组数字 ...
- 一个线上 Maven 诡异问题排查过程
å. 前言 现在的大部分 Java 应用基本都是通过 Maven 进行组织的,不论是分布式应用还是单体集群应用往往都会通过一个 父 POM 加若干子 POM 完成项目的组织.然而这种多应用多模块的拆分 ...
- Hive和Spark分区策略
1.概述 离线数据处理生态系统包含许多关键任务,最大限度的提高数据管道基础设施的稳定性和效率是至关重要的.这边博客将分享Hive和Spark分区的各种策略,以最大限度的提高数据工程生态系统的稳定性和效 ...
- JAVA实现按列表中元素的时间字段排序
JAVA代码实现按列表中元素的时间字段排序 导语: 工作中遇到一个问题,调用第三方接口返回的数据没有按时间倒序排列,测试说要加,然后在网上找到一个解决办法,这里记录一下 需求: 如下图列表,按生日进行 ...
- 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- centos8添加中文语言包
centos8添加中文语言包 系统:centos8 查看: [root@centos8]# locale -a 不支持中文包,按照centos7的方式安装:yum install kde-l10n-C ...
- This application failed to start because no Qt platform plugin could be initialized
今天在直接运行QT生成的.exe遇到了一个错误:This application failed to start because no Qt platform plugin could be init ...