[普通平衡树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.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...
随机推荐
- Elasticsearch 的坑爹事——记录一次mapping field修改过程
Elasticsearch 的坑爹事 本文记录一次Elasticsearch mapping field修改过程 团队使用Elasticsearch做日志的分类检索分析服务,使用了类似如下的_mapp ...
- JAVA使用JDBC技术操作SqlServer数据库执行存储过程
Java使用JDBC技术操作SqlServer数据库执行存储过程: 1.新建SQLSERVER数据库:java_conn_test 2.新建表:tb_User 3.分别新建三个存储过程: 1>带 ...
- python基础之运算符
算术运算符 运算符 描述 实例 + 加 - 两个对象相加 a + b 输出结果 31 - 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -11 * 乘 - 两个数相乘或是返回一个被重复 ...
- mysql,SQL标准,多表查询中内连接,外连接,自然连接等详解之查询结果集的笛卡尔积的演化
先附上数据. CREATE TABLE `course` ( `cno` ) NOT NULL, `cname` ) CHARACTER SET utf8 NOT NULL, `ctime` ) NO ...
- JavaScript事件对象与事件处理程序
在学习之前建议请看一下事件流.事件冒泡.事件捕获 一.事件对象 事件对象:在DOM触发事件时,会产生一个事件对象event,这个事件对象包含着所有与事件相关的信息.既然event是事件对象,那么它必然 ...
- OO方式下,ALV TREE和ALV GRID的不同之处
作为大部分报表程序的基础,ALV GRID差不多是每个ABAP开发者必须了解和掌握的内容,因此网上也不乏相关资料,而ALV TREE的应用相对较少,中文资料也就比较少见了.实际上,ALV TREE和A ...
- iOS 二维码扫描
// 导入 AVFoundation.framwork 框架#import "HDCodeViewController.h" #import "HDNormalViewC ...
- iOS歌词逐渐变色动画
实现歌词逐渐变色的动画,像卡拉OK一样可以根据时间进度来染色.效果如图: 因项目需求要实现一个类似歌词逐渐变色的效果,自己想来想去想不出来实现方案,还是得求助万能的google, 最终是找到了这篇 ...
- iOS开发-UI 从入门到精通(一)
一.UI概述 (1)UI(User Interface)用户界面,用户能看到的各种各样的页面元素: (2)iOS App = 各种各样的UI控件+业务逻辑和算法: (3)想要开发出一款精美的应用程序, ...
- Intent(三)向下一个活动传递数据
向下传递活动很简单,可以我采用putExtra()方法的重载,把我们想要传递的数据暂时放在intent中,启动活动时从这里取就可以了. 首先我们在MainActivity(主活动)显式声明intent ...