文章目录

  • 前言
  • 一、例题 p3369
  • 二、思路及代码
    • 1.思路
    • 2.代码

前言

splay 是 tarjan老爷子的又一发明,解决了平衡树中的很多问题

当然,splay的内容学起来也是很复杂,于是我试着用图的方式将这个算法展示出来

splay实现的数据结构是结构体所维护的二叉树,每个节点保存 父节点,儿子节点,节点权值,权值出现个数,和子树大小这几个信息

旋转过程主要由update(), rotate(), splay() 即 更新函数、旋转函数、splay函数三个函数实现,其分别用来:更新旋转后的子树规模,左旋以及右旋,强制更新至根节点

rotate:


可对照代码一起理解

void rotate(int x) {int y = t[x].fa;int z = t[y].fa;int k = (t[y].child[1] == x);  // 用来判断左旋还是右旋t[z].child[(t[z].child[1] == y)] = x;t[x].fa = z;t[y].child[k] = t[x].child[k ^ 1];t[t[x].child[k ^ 1]].fa = y;t[x].child[k ^ 1] = y;t[y].fa = x;update(y);update(x);
}

splay:
可简要地分为两种情况:


对照代码:

void splay(int x, int s) {while (t[x].fa != s) {  // s 为目标根节点int y = t[x].fa, z = t[y].fa;if (z != s)(t[z].child[0] == y) ^ (t[y].child[0] == x) ? rotate(x) : rotate(y);rotate(x);}if (s == 0) root = x;
}

这四个转化并不是特别显然,但用手画画还是容易理解的

然后是5个功能函数:find(), insert(), maxnext(), delete(), kth(),分别用来:查询排名,二分插入,前继后继查找,删除节点,查询第k大,我们来一一介绍

find():
首先利用平衡树性质递归查找节点,
然后进行splay变换,
排名即为左子树大小

insert():
二分递归查找应插入位置,
然后开点,最后还有splay变换

maxnext():
首先对x进行find()查询排名,
这样x便处于根节点的位置,
其前继和后继节点也很明显

delete():
删除是一个较为复杂的操作,具体步骤如下:
首先找到这个数的前驱,把他Splay到根节点
然后找到这个数后继,把他旋转到前驱的底下
比前驱大的数是后继,在右子树
比后继小的且比前驱大的有且仅有当前数
在后继的左子树上面,
因此直接把当前根节点的右儿子的左儿子删掉就可以

kth():
查询排名第k的数,
其实和find()也很类似,
利用平衡树的性质,
二分查找即可

一、例题 p3369


题目链接:洛谷 p3369

二、思路及代码

1.思路

很经典的平衡树模板,直接套模板即可

借鉴了很多ybb的内容:https://www.cnblogs.com/cjyyb/p/7499020.html

2.代码

代码如下:

#include <iostream>
using namespace std;
const int maxn = 201000;
struct splaytree {int fa, child[2], val, cnt, size;
} t[maxn];  // 父节点,左右子节点,权值,权值出现次数,子树大小
int root, cnt;
void update(int x) {t[x].size = t[t[x].child[0]].size + t[t[x].child[1]].size + t[x].cnt;
}
void rotate(int x) {int y = t[x].fa;int z = t[y].fa;int k = (t[y].child[1] == x);  // 用来判断左旋还是右旋t[z].child[(t[z].child[1] == y)] = x;t[x].fa = z;t[y].child[k] = t[x].child[k ^ 1];t[t[x].child[k ^ 1]].fa = y;t[x].child[k ^ 1] = y;t[y].fa = x;update(y);update(x);
}
void splay(int x, int s) {while (t[x].fa != s) {  // s 为目标根节点int y = t[x].fa, z = t[y].fa;if (z != s)(t[z].child[0] == y) ^ (t[y].child[0] == x) ? rotate(x) : rotate(y);rotate(x);}if (s == 0) root = x;
}
void find(int x) {int u = root;if (!u) return;while (t[u].child[x > t[u].val] && x != t[u].val)u = t[u].child[x > t[u].val];splay(u, 0);
}
void insert(int x) {int u = root, fa = 0;while (u && t[u].val != x) {fa = u;u = t[u].child[x > t[u].val];}if (u)t[u].cnt++;else {u = ++cnt;if (fa) t[fa].child[x > t[fa].val] = u;t[u].child[0] = t[u].child[1] = 0;t[cnt].fa = fa;t[cnt].val = x;t[cnt].cnt = 1;t[cnt].size = 1;}splay(u, 0);
}
int maxnext(int x, int f) {find(x);       // 此时 x 是根节点int u = root;  // f: 0 前继, 1: 后继if (t[u].val > x && f) return u;if (t[u].val < x && !f) return u;u = t[u].child[f];while (t[u].child[f ^ 1]) u = t[u].child[f ^ 1];return u;
}
void Delete(int x) {int last = maxnext(x, 0);int maxnet = maxnext(x, 1);splay(last, 0);splay(maxnet, last);int del = t[maxnet].child[0];if (t[del].cnt > 1) {t[del].cnt--;splay(del, 0);} elset[maxnet].child[0] = 0;
}
int kth(int x) {int u = root;while (t[u].size < x) return 0;while (1) {  // 二分查找int y = t[u].child[0];if (x > t[y].size + t[u].cnt) {x -= t[y].size + t[u].cnt;u = t[u].child[1];} else if (t[y].size >= x)u = y;elsereturn t[u].val;}
}
int main() {//   freopen("in.txt", "r", stdin);//   freopen("out.txt", "w", stdout);int n;scanf("%d", &n);insert(1e9);insert(-1e9);while (n--) {int opt, x;scanf("%d%d", &opt, &x);if (opt == 1) insert(x);if (opt == 2) Delete(x);if (opt == 3) find(x), printf("%d\n", t[t[root].child[0]].size);if (opt == 4) printf("%d\n", kth(x + 1));if (opt == 5) printf("%d\n", t[maxnext(x, 0)].val);if (opt == 6) printf("%d\n", t[maxnext(x, 1)].val);}return 0;
}

图解splay / splay模板 / p3369相关推荐

  1. 图解WordPress主题(模板)架构

    易IT 写道 "Yoast.com制作了一幅讲解Wordpress主题架构的图,非常清晰的剖析了Wordpress的主题模板结构,原图为英文,下面翻译成中文. 中文:图解WordPress主 ...

  2. Tre树(字典树)数据结构详解(图解)及模板

    了解这个数据结构之前我们需要了解它能被用来做什么 字典树又称单词查找树,Tire树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引 ...

  3. 第k短路 算法详解(图解)与模板(A* 算法)

    本博文来自bestsort (转载请保留此信息) A*是一种启发式搜索,根据目标地点和当前点的距离和估计要走的步数来决策下一步走哪个方向.而这两个参数,一般用g(x)g(x)g(x)和h(x)h(x) ...

  4. 伸展树 Splay 模板

    学习Splay的时候参考了很多不同的资料,然而参考资料太杂的后果就是模板调出来一直都有问题,尤其是最后发现网上找的各种资料均有不同程度的错误. 好在啃了几天之后终于算是啃下来了. Splay也算是平衡 ...

  5. [洛谷P3391] 文艺平衡树 (Splay模板)

    初识splay 学splay有一段时间了,一直没写...... 本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列. ...

  6. Splay(splay模板)

    题目描述 给定一个长度为 n 的整数序列,初始时序列为 {1,2,-,n−1,n}. 序列中的位置从左到右依次标号为 1∼n. 我们用 [l,r] 来表示从位置 l 到位置 r 之间(包括两端点)的所 ...

  7. 【模板篇】splay(填坑)+模板题(普通平衡树)

    划着划着水一不小心NOIP还考的凑合了- 所以退役的打算要稍微搁置一下了- 要准备准备省选了-. 但是自己已经啥也不会了- 所以只能重新拾起来- 从splay开始吧- splay我以前扔了个板子来着, ...

  8. BZOJ1500 [NOI2005]维修数列(Splay tree)

    [Submit][Status][Discuss] Description 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线' _ '表示实际输入文件中的空格 Inp ...

  9. poj 3468 Splay 树

    大二上的时候.写过一个AVL的操作演示,今天一看Splay.发现和AVL事实上一样,加上线段树的基础,懒惰标记什么都知道.学起来轻松很多哦 我參考的模板来自这里  http://blog.csdn.n ...

  10. 文艺平衡树(Splay)

    题目背景 这是一道经典的Splay模板题--文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1, ...

最新文章

  1. 6-5-树的双亲表示法-树和二叉树-第6章-《数据结构》课本源码-严蔚敏吴伟民版...
  2. 春节互联网流量峰值破纪录 Gartner最新CDN报告将阿里云评为全球级
  3. IOS UiView frame哪里来?
  4. 按ctrl+shift 无法切换输入法了
  5. yum是干什么的_什么是yum源,yum的工作原理又是什么
  6. HarmonyOS之sdkmgr命令的使用
  7. Elasticsearch 深入3
  8. 请不要对我说“你要马上把这个小问题修改好”
  9. 腾讯智慧出行和现代汽车集团创新中心(北京)正式建立创新战略合作伙伴关系
  10. Ubuntu 安装截图工具Shutter,并设置快捷键 Ctrl+Alt+A
  11. Python自带函数map(),zip()等
  12. PHP连接 SQLSERVER 注意事项(经典中的经典)
  13. Webform(分页、组合查询)
  14. 大数据BI框架知识点备注
  15. 数字图像处理 matlab 报告总结,matlab 数字图像处理实验报告(五份)
  16. 56个民族HTML代码
  17. 全局快门和卷帘快门的区别
  18. 试验设计[实验设计]
  19. [Java,IDEA]连接oracle的关于oracle.jdbc.driver.OracleDriver一直驱动加载失败的原因
  20. OpenGrok简单使用

热门文章

  1. 并发编程之:Atomic
  2. Unity+Kinect 开发脚本介绍
  3. IE主页被2345(782782)篡改解决办法
  4. 2021-2027全球与中国气溶胶粒径谱仪市场现状及未来发展趋势
  5. T-SQL技巧的独孤求败阶段论
  6. 【Java】Response约定
  7. C# 操作Word文本框——插入图片、表格、文字、超链接等
  8. 从罗京、张艺谋看CCTV的知识管理
  9. warning: control reaches end of non-void function [-Wreturn-type]
  10. ETL——实现Kettle作业定时任务