题目传送门

  转载自https://www.cnblogs.com/yousiki/p/6147455.html,转载请注明出处

  

经典引文

空间效率:O(n)
时间效率:O(log n)插入、查找、删除
创造者:Daniel Sleator 和 Robert Tarjan

优点:每次查询会调整树的结构,使被查询频率高的条目更靠近树根。

Tree Rotation

 
树的旋转是splay的基础,对于二叉查找树来说,树的旋转不破坏查找树的结构。
 

Splaying

 
Splaying是Splay Tree中的基本操作,为了让被查询的条目更接近树根,Splay Tree使用了树的旋转操作,同时保证二叉排序树的性质不变。
Splaying的操作受以下三种因素影响:
  • 节点x是父节点p的左孩子还是右孩子
  • 节点p是不是根节点,如果不是
  • 节点p是父节点g的左孩子还是右孩子
同时有三种基本操作:
 

Zig Step


当p为根节点时,进行zip step操作。
当x是p的左孩子时,对x右旋;
当x是p的右孩子时,对x左旋。
 

Zig-Zig Step

当p不是根节点,且x和p同为左孩子或右孩子时进行Zig-Zig操作。
当x和p同为左孩子时,依次将p和x右旋;
当x和p同为右孩子时,依次将p和x左旋。
 
 

Zig-Zag Step

当p不是根节点,且x和p不同为左孩子或右孩子时,进行Zig-Zag操作。
当p为左孩子,x为右孩子时,将x左旋后再右旋。
当p为右孩子,x为左孩子时,将x右旋后再左旋。
 
 

应用

 
Splay Tree可以方便的解决一些区间问题,根据不同形状二叉树中序遍历结果不变的特性,可以将区间按顺序建二叉查找树。
每次自下而上的一套splay都可以将x移动到根节点的位置,利用这个特性,可以方便的利用Lazy的思想进行区间操作。
对于每个节点记录size,代表子树中节点的数目,这样就可以很方便地查找区间中的第k小或第k大元素。
对于一段要处理的区间[x, y],首先splay x-1到root,再splay y+1到root的右孩子,这时root的右孩子的左孩子对应子树就是整个区间。
这样,大部分区间问题都可以很方便的解决,操作同样也适用于一个或多个条目的添加或删除,和区间的移动。

最后附上自己写的洛谷的模板题的代码: 

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e5+;
  4. int n,m,root,tot;
  5. struct Node{
  6. int ch[],size;
  7. int fa,mark,val;
  8. void add(int x,int y){
  9. ch[]=ch[]=mark=;
  10. val=x;fa=y;size=;}
  11. }t[N];
  12. inline int read()
  13. {
  14. char ch=getchar();int num=;bool flag=false;
  15. while(ch<''||ch>''){if(ch=='-')flag=true;ch=getchar();}
  16. while(ch>=''&&ch<=''){num=num*+ch-'';ch=getchar();}
  17. return flag?-num:num;
  18. }
  19. inline void pushup(int x)
  20. {
  21. int l=t[x].ch[],r=t[x].ch[];
  22. t[x].size=t[l].size+t[r].size+;
  23. }
  24. inline void pushdown(int x)
  25. {
  26. if(t[x].mark){
  27. t[t[x].ch[]].mark^=;
  28. t[t[x].ch[]].mark^=;
  29. swap(t[x].ch[],t[x].ch[]);
  30. t[x].mark=;}
  31. }
  32. inline void rotate(int x)
  33. {
  34. int y=t[x].fa;
  35. int z=t[y].fa;
  36. int k=(t[y].ch[]==x);
  37. t[z].ch[t[z].ch[]==y]=x;
  38. t[x].fa=z;
  39. t[t[x].ch[k^]].fa=y;
  40. t[y].ch[k]=t[x].ch[k^];
  41. t[x].ch[k^]=y;
  42. t[y].fa=x;
  43. pushup(y);pushup(x);
  44. }
  45. inline void splay(int x,int tag)
  46. {
  47. while(t[x].fa!=tag){
  48. int y=t[x].fa;
  49. int z=t[y].fa;
  50. if(z!=tag)
  51. (t[y].ch[]==x)^(t[z].ch[]==y)?
  52. rotate(x):rotate(y);
  53. rotate(x);
  54. }
  55. if(tag==)root=x;
  56. }
  57. inline void insert(int x)
  58. {
  59. int now=root,fa=;
  60. while(now)
  61. fa=now,now=t[now].ch[x>t[now].val];
  62. now=++tot;
  63. if(fa)t[fa].ch[x>t[fa].val]=now;
  64. t[now].add(x,fa);
  65. splay(now,);
  66. }
  67. inline int find(int x)
  68. {
  69. int now=root;
  70. while(){
  71. pushdown(now);
  72. if(t[t[now].ch[]].size>=x)now=t[now].ch[];
  73. else if(t[t[now].ch[]].size+==x)return now;
  74. else x-=(t[t[now].ch[]].size+),now=t[now].ch[];
  75. }
  76. }
  77. inline void work(int l,int r)
  78. {
  79. l=find(l);r=find(r+);
  80. splay(l,);splay(r,l);
  81. t[t[t[root].ch[]].ch[]].mark^=;
  82. }
  83. inline void print(int x)
  84. {
  85. pushdown(x);
  86. if(t[x].ch[])print(t[x].ch[]);
  87. if(t[x].val>&&t[x].val<n+)
  88. printf("%d ",t[x].val-);
  89. if(t[x].ch[])print(t[x].ch[]);
  90. }
  91. int main()
  92. {
  93. n=read();m=read();
  94. for(int i=;i<=n+;i++)
  95. insert(i);
  96. for(int i=;i<=m;i++){
  97. int l=read();int r=read();
  98. work(l,r);}
  99. print(root);
  100. return ;
  101. }

洛谷P3391文艺平衡树(Splay)的更多相关文章

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

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

  2. BZOJ3223/洛谷P3391 - 文艺平衡树

    BZOJ链接 洛谷链接 题意 模板题啦~2 代码 //文艺平衡树 #include <cstdio> #include <algorithm> using namespace ...

  3. BZOJ3224/洛谷P3391 - 普通平衡树(Splay)

    BZOJ链接 洛谷链接 题意简述 模板题啦~ 代码 //普通平衡树(Splay) #include <cstdio> int const N=1e5+10; int rt,ndCnt; i ...

  4. 洛谷 P3391 文艺平衡树

    题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 --b ...

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

    模板题. 注意标记即可,另外,涉及区间翻转操作,记得设立首尾哨兵. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int ...

  6. 洛谷.3391.文艺平衡树(fhq Traep)

    题目链接 //注意反转时先分裂r,因为l,r是针对整棵树的排名 #include<cstdio> #include<cctype> #include<algorithm& ...

  7. 洛谷 P3391 【模板】文艺平衡树(Splay)

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

  8. 【阶梯报告】洛谷P3391【模板】文艺平衡树 splay

    [阶梯报告]洛谷P3391[模板]文艺平衡树 splay 题目链接在这里[链接](https://www.luogu.org/problemnew/show/P3391)最近在学习splay,终于做对 ...

  9. [luogu P3391] 文艺平衡树

    [luogu P3391] 文艺平衡树 题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区 ...

随机推荐

  1. [LeetCode] 2. Add Two Numbers ☆☆

    You are given two non-empty linked lists representing two non-negative integers. The digits are stor ...

  2. python实现堆栈、队列

    一.利用python列表实现堆栈和队列 堆栈: 堆栈是一个后进先出的数据结构,其工作方式就像生活中常见到的直梯,先进去的人肯定是最后出. 我们可以设置一个类,用列表来存放栈中的元素的信息,利用列表的a ...

  3. gitlab通过api创建组、项目、成员

    前戏 获取gitlab中admin用户的private_token Groups API 获取某个组的详细 curl --header "PRIVATE-TOKEN: *********&q ...

  4. CAS单点登录原理

    转自 https://www.cnblogs.com/lihuidu/p/6495247.html 1.基于Cookie的单点登录的回顾        基于Cookie的单点登录核心原理: 将用户名密 ...

  5. 深入理解微服务架构spring的各个知识点(面试必问知识点)

    什么是spring spring是一个开源框架,spring为简化企业级开发而生,使用spring可以使简单的java bean 实现以前只有EJG才能实现的功能. Spring是一个轻量级的控制反转 ...

  6. bzoj 1004 burnside 引理+DP

    对于burnside引理需要枚举染色,这道题属于burnside的一种简单求解的方法,就是polya,我们可以使每一种置换中的循环节中的元素的颜色都相同,那么这样的话就可以直接DP了,我们可以将m个置 ...

  7. Python面向对象学习2(面向对象的语法和特性,待更新)

    上一个内容我们介绍了面向对象和面向对象场景现在我们来学习下语法和特性 1,面向对象基本语法: # -*- coding:utf-8 -*- # Author: Colin Yao class Dog( ...

  8. ftrace 的使用【转】

    转自:http://blog.csdn.net/wang6077160/article/details/7814279 ftrace 的使用 ftrace 在内核态工作,用户通过 debugfs 接口 ...

  9. sicily 1036. Crypto Columns

    Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description The columnar encryption scheme scram ...

  10. 设计模式之笔记--组合模式(Composite)

    组合模式(Composite) 定义 组合模式(Composite),将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性.       组合模式有 ...