[普通平衡树splay]【学习笔记】
参考:
http://blog.csdn.net/clove_unique/article/details/50630280
gty课件
找一个好的风格太难了,自己习惯用struct,就强行用struct写了一下数组版的,同时加了些宏简化代码
都是迭代写法
splay要维护fa指向父亲
rotate是把x转到fa,要更新f和x
splay是把x转到tar的孩子,x成为root就是tar=0,注意更新root
ins考虑空树,考虑已经存在,插入新节点的话要保留last到最后处理父亲,然后做splay
(递归写法的传引用已经解决了设置祖先的问题)
del
先找要删除的,splay到根
1.多个直接--
2.空树直接root=0
3.只有一个儿子,令独生子变成根,删去该点。
4.左右儿子都有。找到左子树中权值最大的点,将其 splay 到左儿子的位置。然后将 整棵右子树挂在左儿子的右边。删除节点。
其他操作差不多了
ps:比treap慢了一倍
//
// main.cpp
// splay
//
// Created by Candy on 27/11/2016.
// Copyright © 2016 Candy. All rights reserved.
// #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=2e5+;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
struct node{
int fa,ch[],v,w,size;
}t[N];
int cnt,root;
inline int wh(int x){return t[pa].ch[]==x;}
inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
inline void rotate(int x){//x-->pa
int f=t[x].fa,g=t[f].fa,c=wh(x);
if(g) t[g].ch[wh(f)]=x;
t[f].ch[c]=t[x].ch[c^];t[t[f].ch[c]].fa=f;
t[x].ch[c^]=f;t[f].fa=x;
t[x].fa=g;
update(f);update(x);
}
inline void splay(int x,int tar){//x-->x.fa==tar
for(;t[x].fa!=tar;rotate(x))
if(t[pa].fa!=tar) rotate(wh(x)==wh(pa)?pa:x);
if(tar==) root=x;
} inline int nw(int v){
cnt++;
t[cnt].v=v;t[cnt].ch[]=t[cnt].ch[]=t[cnt].fa=;
t[cnt].w=t[cnt].size=;
return cnt;
}
inline void ins(int v){
if(root==){root=nw(v);return;}//empty tree
int x=root,last=;
while(x!=){
if(t[x].v==v){t[x].w++;t[x].size++;splay(x,);return;}
last=x;
if(v<t[x].v) x=lc; else x=rc;
}
int tmp=nw(v);
if(v<t[last].v) t[last].ch[]=tmp;
else t[last].ch[]=tmp;
t[tmp].fa=last;update(last);//no need for ancient because splay()
splay(tmp,);
}
inline int find(int v){
int x=root;
while(x!=){
if(v==t[x].v) break;
if(v<t[x].v) x=lc;
else x=rc;
}
if(x!=) splay(x,);
return x;
}
inline int pre(){
int x=t[root].ch[];
while(rc) x=rc;
return x;
}
inline void del(int v){
int x=find(v);
if(t[x].w>) {t[x].w--,t[x].size--;return;}
if(lc==&&rc==) root=;
else if(rc==) t[lc].fa=,root=lc;
else if(lc==) t[rc].fa=,root=rc;
else{
int tmp=t[root].ch[];
while(t[tmp].ch[]) tmp=t[tmp].ch[];
splay(tmp,x);
t[tmp].ch[]=rc;t[rc].fa=tmp;
t[tmp].fa=;
root=tmp;
update(root);
}
}
inline int rnk(int v){
int x=root,ls=;
while(x!=){
if(t[x].v==v){
int ans=ls+t[lc].size+;
splay(x,);
return ans;
}
if(v<t[x].v) x=lc;
else ls+=t[lc].size+t[x].w,x=rc;
}
return -;
}
inline int kth(int k){
int x=root,ls=;
while(x!=){
int tmp=ls+t[lc].size;
if(tmp+<=k&&k<=tmp+t[x].w){
splay(x,);return t[x].v;
}
if(k<=tmp) x=lc;
else ls=tmp+t[x].w,x=rc;
}
return -;
}
inline int pre(int v){
int ans=,x=root;
while(x!=){
if(t[x].v<v) ans=x,x=rc;
else x=lc;
}
return ans;
}
inline int suf(int v){
int ans=,x=root;
while(x!=){//printf("suf %d %d\n",x,t[x].v);
if(v<t[x].v) ans=x,x=lc;
else x=rc;
}
return ans;
}
int n,op,x,ans;
int main(int argc, const char * argv[]){
n=read();
while(n--){
op=read();x=read();
switch(op){
case :ins(x);break;
case :del(x);break;
case :printf("%d\n",rnk(x));break;
case :printf("%d\n",kth(x));break;
case :ans=pre(x);printf("%d\n",t[ans].v);break;
case :ans=suf(x);printf("%d\n",t[ans].v);break;
}
}
return ;
}
[2016-11-30]
复习了一遍
注意:
find和ins操作要splay,有的地方直接return的话忘记splay了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=2e5+;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
struct node{
int fa,ch[],w,size,v;
}t[N];
int cnt,root;
inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
inline int wh(int x){return t[pa].ch[]==x;}
inline void rotate(int x){
int f=t[x].fa,g=t[f].fa,c=wh(x);
if(g) t[g].ch[wh(f)]=x;t[x].fa=g;
t[f].ch[c]=t[x].ch[c^];t[t[f].ch[c]].fa=f;
t[x].ch[c^]=f;t[f].fa=x;
update(f);update(x);
}
inline void splay(int x,int tar){
for(;t[x].fa!=tar;rotate(x))
if(t[pa].fa!=tar) rotate(wh(pa)==wh(x)?pa:x);
if(tar==) root=x;
}
inline int nw(int v){
cnt++;
t[cnt].ch[]=t[cnt].ch[]=t[cnt].fa=;
t[cnt].w=t[cnt].size=;t[cnt].v=v;
return cnt;
}
void ins(int v){
if(root==){root=nw(v);return;}
int x=root,last=;
while(x){
if(t[x].v==v){t[x].w++;t[x].size++;splay(x,);return;}
last=x;
if(v<t[x].v) x=lc;else x=rc;
}
int _=nw(v);
if(v<t[last].v) t[last].ch[]=_;
else t[last].ch[]=_;
t[_].fa=last;
splay(_,);
}
int find(int v){
int x=root;
while(x){
if(t[x].v==v) break;//not return cause splay
if(v<t[x].v) x=lc;else x=rc;
}
if(x!=) splay(x,);
return x;
}
void del(int v){
int x=find(v);
if(t[x].w>){t[x].w--;t[x].size--;return;}
if(lc==&&rc==) root=;
else if(rc==) t[lc].fa=,root=lc;
else if(lc==) t[rc].fa=,root=rc;
else{
int _=lc;
while(t[_].ch[]) _=t[_].ch[];
splay(_,x);
t[_].ch[]=rc;t[rc].fa=_;
t[_].fa=;root=_;
update(root);
}
}
int rnk(int v){
int x=root,ls=;
while(x){
if(t[x].v==v){
int ans=ls+t[lc].size+;
splay(x,);
return ans;
}
if(v<t[x].v) x=lc;else ls+=t[lc].size+t[x].w,x=rc;
}
return -;
}
int kth(int k){
int x=root,ls=;
while(x){
int _=ls+t[lc].size;
if(_<k&&k<=_+t[x].w) return t[x].v;
if(k<=_) x=lc;
else ls=_+t[x].w,x=rc;
}
return -;
}
int pre(int v){
int x=root,ans=;
while(x){
if(v>t[x].v) ans=x,x=rc;
else x=lc;
}
return ans;
}
int suf(int v){
int x=root,ans=;
while(x){
if(v<t[x].v) ans=x,x=lc;
else x=rc;
}
return ans;
}
int n,op,x,ans;
int main(int argc, const char * argv[]){
n=read();
while(n--){
op=read();x=read();
switch(op){
case :ins(x);break;
case :del(x);break;
case :printf("%d\n",rnk(x));break;
case :printf("%d\n",kth(x));break;
case :ans=pre(x);printf("%d\n",t[ans].v);break;
case :ans=suf(x);printf("%d\n",t[ans].v);break;
}
}
return ;
}
[普通平衡树splay]【学习笔记】的更多相关文章
- 平衡树splay学习笔记#2
讲一下另外的所有操作(指的是普通平衡树中的其他操作) 前一篇的学习笔记连接:[传送门],结尾会带上完整的代码. 操作1,pushup操作 之前学习过线段树,都知道子节点的信息需要更新到父亲节点上. 因 ...
- 平衡树splay学习笔记#1
这一篇博客只讲splay的前一部分的操作(rotate和splay),后面的一段博客咕咕一段时间 后一半的博客地址:[传送门] 前言骚话 为了学lct我也是拼了,看了十几篇博客,学了将近有一周,才A掉 ...
- 文艺平衡树 Splay 学习笔记(1)
(这里是Splay基础操作,reserve什么的会在下一篇里面讲) 好久之前就说要学Splay了,结果苟到现在才学习. 可能是最近良心发现自己实在太弱了,听数学又听不懂只好多学点不要脑子的数据结构. ...
- 【洛谷P3369】普通平衡树——Splay学习笔记(一)
二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...
- 【洛谷P3391】文艺平衡树——Splay学习笔记(二)
题目链接 Splay基础操作 \(Splay\)上的区间翻转 首先,这里的\(Splay\)维护的是一个序列的顺序,每个结点即为序列中的一个数,序列的顺序即为\(Splay\)的中序遍历 那么如何实现 ...
- [Splay][学习笔记]
胡扯 因为先学习的treap,而splay与treap中有许多共性,所以会有很多地方不会讲的很细致.关于treap和平衡树可以参考这篇博客 关于splay splay,又叫伸展树,是一种二叉排序树,它 ...
- [Note]Splay学习笔记
开个坑记录一下学习Splay的历程. Code 感谢rqy巨佬的代码,让我意识到了Splay可以有多短,以及我之前的Splay有多么的丑... int fa[N], ch[N][2], rev[N], ...
- splay学习笔记
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.(来自百科) 伸展树的操作主要是 –rotate(x) 将x旋转到x的父亲的位置 voi ...
- Treap-平衡树学习笔记
平衡树-Treap学习笔记 最近刚学了Treap 发现这种数据结构真的是--妙啊妙啊~~ 咳咳.... 所以发一发博客,也是为了加深蒟蒻自己的理解 顺便帮助一下各位小伙伴们 切入正题 Treap的结构 ...
- [学习笔记]平衡树(Splay)——旋转的灵魂舞蹈家
1.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...
随机推荐
- PHP中抽象类,接口定义
这里先介绍接口,因为在我最近看的好几本php工具书中都没有提到抽象类. 本人也觉得,在理解了接口后抽象类也非常好理解. 例子代码随便写了一下.例子代码是很ok的,测试过了不会报错,懒得看代码的筒靴们看 ...
- 解决WIN7与虚拟机CentOS的文件夹共享问题
一.系统与软件 WIN7 64bit.VirtualBox 5.0.14.CentOS 6.5.SecureCRT 7.2.3 二.使用文件夹共享需要安装增强功能,但是安装时无法读取光盘iso文件 三 ...
- JavaScript判断变量值简单的方法
今天在看一个动态web表单设计器的时候发现项目中的 一个写法 function sum_total(v){ if (!v) { v= 0; } } !v 这是什么写法?不过可以肯定的是,这是一种判断 ...
- SharePoint 2013 工作流平台的选项不可用
问题描述 当我想创建一个SharePoint 2013 工作流的时候,打开SharePoint 2013 Designer(一下简称SPD),发现没有SharePoint 2013 工作流的选项.原来 ...
- 将oracle冷备份恢复到另外一个数据库实例中
因更换服务器需要将Oracle数据库转移到另外台Oracle中.说明: 1.测试环境为:windows server2003 和 oracle 10g. 2.2台服务器安装的程序目录一样,数据目录不一 ...
- Shou 团队诚意满满的招募 Swifter
一.团队介绍 团队产品 VPlayer 播放器靠自增长 3 年内获得全球 4000 万用户,开发的 Vitamio 组件更是获得微博.UC.金山等知名企业授权使用.—— 团队再次起航,经历一年多我们已 ...
- Linux - expect自动化远程登录脚本
简单模式: #!/usr/bin/expect -f spawn ssh root@192.168.0.1 expect "*assword*" send "root\r ...
- Ruby的模型关系随笔
1 Class和Module的实例方法也就是所有具体类和具体Module的类方法,因为具体类和具体Module分别是Class和Module的实例.例如Object.new对应着Class#new,K ...
- css sprite简便方法切 《评分五角星》
摘抄自我趣同伴的心得: 大家可以会遇到过要做满意度用星级来评分的情况,类似这种 实现的方法有很多,大家最初想到的可能是根据满意度有多少种情况就切多少种图,然后拼在一张图里面,通过控制图片的位置来实现. ...
- ns3重要类
1. simple-ref-count 递归模板,使得通过定义T:SimpleRefCount<T>使得T类都具有计数功能 template <typename T, typenam ...