【总结】 伸展树Splay
挖坑待补
前言
感觉我在联赛还差4天的时候学习Splay有点慌,但还是要学一下。
定义
我们先对Splay的数组进行一些定义:
struct node{
int ff,siz,cnt,ch[2],val;
//ff表示父亲,siz表示子树大小,ch表示儿子,cnt表示与这个点权值相同的点的个数,val表示权值。
}t[N<<2];
操作
我们的Splay应该要支持以下几个操作:
- 插入
- 删除
- 查找排名为k的数
- 查找k的排名
- 查找k的前驱
- 查找k的后继
- 分裂(不会)
- 合并(启发式合并)
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
int root,tot;
inline int gi(){
int sum=0,f=1;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
class SplayTree{
private:
struct node{
int ff,siz,cnt,ch[2],val;
//ff表示父亲,siz表示子树大小,ch表示儿子,cnt表示与这个点权值相同的点的个数,val表示权值。
}t[N<<2];
inline void pushup(int x){t[x].siz=t[x].cnt+t[t[x].ch[0]].siz+t[t[x].ch[1]].siz;}
inline void rotate(int x){
int y=t[x].ff,z=t[y].ff;
int k=(x==t[y].ch[1]);
t[z].ch[y==t[z].ch[1]]=x;
t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];
t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;
t[y].ff=x;
pushup(y);pushup(x);
}
public:
inline void Splay(int x,int goal){
while(t[x].ff!=goal){
int y=t[x].ff,z=t[y].ff;
if(z!=goal)
(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
rotate(x);
}
if(!goal)root=x;
}
inline void find(int x){
int u=root;
if(!u)return;
while(t[u].val!=x && t[u].ch[x>t[u].val])
u=t[u].ch[x>t[u].val];
Splay(u,0);
}
inline void Insert(int x){
int u=root,ff=0;
while(u && t[u].val!=x){ff=u;u=t[u].ch[x>t[u].val];}
if(u)t[u].cnt++;
else{
u=++tot;
t[u].cnt=t[u].siz=1;t[u].val=x;
t[u].ff=ff;t[u].ch[0]=t[u].ch[1]=0;
if(ff)t[ff].ch[x>t[ff].val]=u;
}
Splay(u,0);
}
inline int Next(int x,int f){//f=1表示后继,f=0表示前驱
find(x);
int u=root;
if(t[u].val>x && f)return u;
if(t[u].val<x && !f)return u;
u=t[u].ch[f];
while(t[u].ch[f^1])u=t[u].ch[f^1];
return u;
}
inline void Delete(int x){
int last=Next(x,0),nxt=Next(x,1);
Splay(last,0);Splay(nxt,last);
int del=t[nxt].ch[0];
if(t[del].cnt>1){t[del].cnt--;Splay(del,0);}
else t[nxt].ch[0]=0;
}
inline int kth(int x){
int u=root;
if(t[u].siz<x)return 0;
while(1){
int y=t[u].ch[0];
if(t[y].siz<x && t[y].siz+t[u].cnt>=x)return t[u].val;
if(t[y].siz>=x)u=y;
else{
x-=t[y].siz+t[u].cnt;
u=t[u].ch[1];
}
}
}
inline int Val(int u){
return t[u].val;
}
inline int ch0size(){
return t[t[root].ch[0]].siz;
}
}Splay;
int main(){
int n=gi();
Splay.Insert(2147483647);
Splay.Insert(-2147483648);
while(n--){
int opt=gi(),x=gi();
if(opt==1)Splay.Insert(x);
if(opt==2)Splay.Delete(x);
if(opt==3){
Splay.find(x);
printf("%d\n",Splay.ch0size());
}
if(opt==4)printf("%d\n",Splay.kth(x+1));
if(opt==5)printf("%d\n",Splay.Val(Splay.Next(x,0)));
if(opt==6)printf("%d\n",Splay.Val(Splay.Next(x,1)));
}
return 0;
}
【总结】 伸展树Splay的更多相关文章
- 树-伸展树(Splay Tree)
伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...
- 纸上谈兵: 伸展树 (splay tree)[转]
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每 ...
- K:伸展树(splay tree)
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...
- 高级搜索树-伸展树(Splay Tree)
目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...
- 【BBST 之伸展树 (Splay Tree)】
最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...
- [Splay伸展树]splay树入门级教程
首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...
- 伸展树Splay【非指针版】
·伸展树有以下基本操作(基于一道强大模板题:codevs维护队列): a[]读入的数组;id[]表示当前数组中的元素在树中节点的临时标号;fa[]当前节点的父节点的编号;c[][]类似于Trie,就是 ...
- 伸展树(Splay tree)的基本操作与应用
伸展树的基本操作与应用 [伸展树的基本操作] 伸展树是二叉查找树的一种改进,与二叉查找树一样,伸展树也具有有序性.即伸展树中的每一个节点 x 都满足:该节点左子树中的每一个元素都小于 x,而其右子树中 ...
- ZOJ 3765 Lights (zju March I)伸展树Splay
ZJU 三月月赛题,当时见这个题目没辙,没学过splay,敲了个链表TLE了,所以回来好好学了下Splay,这道题目是伸展树的第二题,对于伸展树的各项操作有了更多的理解,这题不同于上一题的用指针表示整 ...
- [数据结构]伸展树(Splay)
#0.0 写在前面 Splay(伸展树)是较为重要的一种平衡树,理解起来也依旧很容易,但是细节是真的多QnQ,学一次忘一次,还是得用博客加深一下理解( #1.0 Splay! #1.1 基本构架 Sp ...
随机推荐
- GitHub从注册到使用
GitHub是最流行的代码库,里面存储着丰富的优秀的开源代码,不仅如此,作为一款免费的代码存储利器也是很牛逼,支持各种编程语言,代码显示效果堪称完美,可以随时随地查看自己记录的笔记 GitHub的好处 ...
- Unity脚本开发基础 C#
1. MonoBehaviour 类 常用事件响应函数: 2. 访问游戏对象 (1) 通过名称来查找 (2) 通过标签来查找 上述函数比较费时,应避免在 Update 函数调用. 3. 访问组件 对于 ...
- Linux 登陆提示文字
/etc/issue是从本地登陆显示的信息 /etc/issue.net是从网络登陆显示的信息 /etc/motd内容由系统管理员确定,常用于通告信息,如计划关机时间的警告等 每次用户登录时,/etc ...
- pid文件的作用
pid文件的作用 一.pid文件的作用 1.pid文件的内容用cat命令查看,可以看到内容只有一行,记录了该进程的ID 2.pid文件的作用防止启动多个进程副本 3.pid文件的原理进程运行后会给.p ...
- Sso单点登录分析
1. Sso系统分析 1.1. 什么是sso系统 SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这 ...
- shell-array
[shell-array] Creating Array: $ names=("Bob" "Peter" "$USER" "Big ...
- 浅析 python中的 print 和 input 的底层区别!!!
近期的项目中 涉及到相关知识 就来总结一下 ! 先看源码: def print(self, *args, sep=' ', end='\n', file=None): # known special ...
- MongoDB 数组操作
$push:向文档数组中添加元素,如果没有该数组,则自动添加数组.db.users.insert({"name":"zhang"})db.users.updat ...
- c++ 享元模式(flyweight)
举个围棋的例子,围棋的棋盘共有361格,即可放361个棋子.现在要实现一个围棋程 序,该怎么办呢?首先要考虑的是棋子棋盘的实现,可以定义一个棋子的类,成员变量包括棋子的颜色.形状.位置等信息,另外再定 ...
- 监控服务器cpu、磁盘、模板以及自定义key
一.检测主机存活 net.tcp.service.perf[tcp,,] Float型 返回0代表端口挂了 zabbix fping要开启sudo权限之类比较不方便 二.监控CPU负载 监控load ...