声明:本博客所有随笔都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。

前言

终于学习了 spaly \(splay\) !听说了很久,因为dalao总是那这个开玩笑所以对它有深深的恐惧...但是学起来没有那么难啦,可能是因为提前学了替罪羊树?(学替罪羊树真的是痛苦555)

模板

P3369 【模板】普通平衡树

固定变量:

\(edge\) - 这个节点的值

\(tot\) - 这个节点重复的数

\(son[0/1]\) - 左儿子右儿子

\(fa\) - 节点的父亲

\(size\) - 子树的大小

  1. struct ndoe{
  2. int tot, size, son[2], fa, edge;
  3. }tree[N];

add(x)(添加一个点):

1.找到特殊点

2.判断 \(x\) 与特殊节点的值

\ \ 1)相等,则直接 \(++ \ tot\)

\ \ 2)不相等,则新建节点,更新变量

  1. void add(int x)
  2. {
  3. int u = root, fa = 0;
  4. while(u && tree[u].edge != x)
  5. fa = u, u = tree[u].son[x > tree[u].edge];
  6. if(u) ++ tree[u].tot;
  7. else
  8. {
  9. u = ++ num;
  10. if(fa) tree[fa].son[x > tree[fa].edge] = u;
  11. tree[u].edge = x, tree[u].size = tree[u].tot = 1, tree[u].fa = fa;
  12. }
  13. splay(u, 0);
  14. }

del(x)(删除一个点):

1.找到 \(x\) 的前驱后继

2.把前驱 \(splay\) 至根节点,把后继 \(splay\) 成前驱的儿子

3.此时后继的左儿子则为要删除的点,判断此节点的个数

\ \ 1)个数大于一则只用去掉一个,然后 \(splay\)

\ \ 2)个数为一则直接删掉

  1. void del(int x)
  2. {
  3. int xpre = next(x, 0), xnxt = next(x, 1);
  4. splay(xpre, 0), splay(xnxt, xpre);
  5. int u = tree[xnxt].son[0];
  6. if(tree[u].tot > 1) -- tree[u].tot, splay(u, 0);
  7. else tree[xnxt].son[0] = 0;
  8. }

splay(x, goal)(将 \(x\) 旋成 \(goal\) 的儿子):

1.判断 \(x\) 是否是 \(goal\) 的儿子

\ \ 1)不是,则判断 \(x\) 和它的父亲、祖先是否在一条线上,进行不同的 \(splay\)

\ \ 2)是,判断 \(x\) 是否是根并更新

  1. void splay(int x, int goal)
  2. {
  3. while(tree[x].fa != goal)
  4. {
  5. int y = tree[x].fa, z = tree[y].fa;
  6. if(z != goal) ((tree[z].son[0] == y) ^ (tree[y].son[0] == x)) ? rotate(x) : rotate(y);
  7. rotate(x);
  8. }
  9. if(! goal) root = x;
  10. }

rotate(x)(单旋):

1.更新 \(x\) 和 \(z\) 的父子关系

2.更新 \(y\) 和 ( \(x\) 原来和 \(y\) 对应的那个儿子)的父子关系

3.更新 \(x\) 和 \(y\) 的父子关系

4.\(update \ x、y\)

  1. void rotate(int x)
  2. {
  3. int y = tree[x].fa, z = tree[y].fa, k = (tree[y].son[1] == x);
  4. tree[z].son[tree[z].son[1] == y] = x, tree[x].fa = z;
  5. tree[y].son[k] = tree[x].son[k ^ 1], tree[tree[x].son[k ^ 1]].fa = y;
  6. tree[x].son[k ^ 1] = y, tree[y].fa = x;
  7. update(y), update(x);
  8. }

pre(x)(前驱):

1.将 \(x\) 变为树根

2.有左子树则进入左子树,没有则代表没有比它小的数了

3.进入左子树后一路往右子树上凑(找最大的)

nxt(x)(后继):

1.将 \(x\) 变为树根

2.有右子树则进入右子树,没有则代表没有比它大的数了

3.进入右子树后一路往左子树上凑(找最小的)

  1. int next(int x, int f)//我把pre和nxt写到一起啦,实际上是一样的
  2. {
  3. find(x);
  4. int u = root;
  5. if((tree[u].edge > x && f) || (tree[u].edge < x && (! f))) return u;
  6. u = tree[u].son[f];
  7. while(tree[u].son[f ^ 1]) u = tree[u].son[f ^ 1];
  8. return u;
  9. }

find(x)(辅助函数):

1.找到值等于 \(x\) 的那个节点

2.将节点旋转至树根

  1. void find(int x)
  2. {
  3. int u = root;
  4. if(! u) return;
  5. while(tree[u].son[x > tree[u].edge] && tree[u].edge != x)
  6. u = tree[u].son[x > tree[u].edge];
  7. splay(u, 0);
  8. }

query(x)(第k大的数):

1.先判断整个树的 \(size\) 是否大于等于 \(x\),若没有则不存在

2.分三种情况继续讨论:

\ \ 1)左子树 \(size\) 大于 \(x\) ,前往左子树

\ \ 2)左子树+这个节点的数的个数大于 \(x\),则直接返回这个节点的值

\ \ 3)更新 \(x\),前往右子树

  1. int query(int x)
  2. {
  3. int u = root;
  4. if(tree[u].size < x) return 0;
  5. while(1)
  6. {
  7. int y = tree[u].son[0];
  8. if(x <= tree[y].size) u = y;
  9. else if(x <= tree[y].size + tree[u].tot) return tree[u].edge;
  10. else x -= (tree[y].size + tree[u].tot), u = tree[u].son[1];
  11. }
  12. }

【学习笔记】splay入门(更新中)的更多相关文章

  1. 【转】git 学习笔记( 随时更新中…… 最后更新日期201304281518)--不错

    原文网址:http://blog.csdn.net/yasin_lee/article/details/5975070 GIT 是版本管理的未来!   推荐几个GIT教程网站 http://www-c ...

  2. Oracle 9i & 10g编程艺术-深入数据库体系结构-学习笔记(持续更新中)

    --20170322 --1.0 --更新表的统计信息begin dbms_stats.set_table_stats(user,'EMP',numrows => 10000);end; beg ...

  3. HTML5学习笔记(持续更新中....)

    平时的工作中,不知不觉我们应用了很多HTML5,但当正儿八经问起来你对HTML5了解多少,很多时候都有点懵. 做个简单的HTML5总结.包括简介.要学的知识点.凌乱的知识点 HMTL5简介 定义:ht ...

  4. Gradle项目构建工具学习笔记(持续更新中。。。)

    1.gradle的安装 1)从官网下载gradle,然后解压 2)在系统环境变量新建GRADLE_HOME 3)将%GRADLE_HOME%\bin加入PATH中 2.验证是否安装成功 gradle ...

  5. [斜率优化DP]【学习笔记】【更新中】

    参考资料: 1.元旦集训的课件已经很好了 http://files.cnblogs.com/files/candy99/dp.pdf 2.http://www.cnblogs.com/MashiroS ...

  6. python学习笔记--Django入门四 管理站点--二

    接上一节  python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...

  7. DBFlow框架的学习笔记之入门

    什么是DBFlow? dbflow是一款android高性的ORM数据库.可以使用在进行项目中有关数据库的操作.github下载源码 1.环境配置 先导入 apt plugin库到你的classpat ...

  8. MongoDB学习笔记:快速入门

    MongoDB学习笔记:快速入门   一.MongoDB 简介 MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统.在高负载的情况下,添加更多的节点,可以保证服务器性能.M ...

  9. HTML语言学习笔记(会更新)

    # HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...

  10. WebSocket学习笔记——无痛入门

    WebSocket学习笔记——无痛入门 标签: websocket 2014-04-09 22:05 4987人阅读 评论(1) 收藏 举报  分类: 物联网学习笔记(37)  版权声明:本文为博主原 ...

随机推荐

  1. 初步进入linux世界

    [Linux 系统启动过程] Linux的启动其实和windows的启动过程很类似,不过windows我们是无法看到启动信息的,而linux启动时我们会看到许多启动信息,例如某个服务是否启动. Lin ...

  2. 配置centOS下的Python

    Linux下Python版本升级: 1. 首先确认Linux操作系统中自带的python 版本时候与自己所需要的版本一致 所有的python版本都在https://www.python.org/ftp ...

  3. centos7中安装mysql

    centos7中安装mysql网上已经很多资源了,我就不在赘述了.我这里只是记录下我安装的时候出现的一些问题. 原文:https://www.cnblogs.com/bigbrotherer/p/72 ...

  4. DOM--选取文档元素

    大多数的客户端JavaScript程序在运行时都是在操作一个或者多个文档元素,而为了操作文档中的元素我们就必须要通过某种途径或者方法获得或者选取这些引用文档元素的Element对象.DOM定义了许多种 ...

  5. Flask 和Django

    软件系统发展到今天已经很复杂了,在服务端软件,设计的知识很广泛,为了降低开发难度,提高开发效率,在某些方面去使用别人成熟的框架. 一些事务处理,安全性,数据流控制等都可以让框架处理,而开发人员把更多的 ...

  6. 浅谈 PCA与SVD

    前言 在用数据对模型进行训练时,通常会遇到维度过高,也就是数据的特征太多的问题,有时特征之间还存在一定的相关性,这时如果还使用原数据训练模型,模型的精度会大大下降,因此要降低数据的维度,同时新数据的特 ...

  7. 使用Cloudflare增强网站

    Cloudflare Cloudflare是美国的一家网络性能和安全公司,近期由于自己域名HTTP证书到期,了解到了Cloudflare,用到了它提供的CDN以及SSL 如何设置CDN 登入Cloud ...

  8. django-生产和测试环境分离

    django-生产和测试环境分离 在settings.py的同级目录下新建settings的文件夹 在settings文件夹下新建 __init__.py base.py develop.py pro ...

  9. C语言 文件操作(六)

    一.fseek() int fseek(FILE * stream, long offset, int whence); 1.参数stream 为已打开的文件指针. 2.参数offset 是偏移量,该 ...

  10. javascript入门 之 ztree (八 一系列鼠标事件)

    <!DOCTYPE html> <HTML> <HEAD> <meta http-equiv="content-type" content ...