学完Splay的查找作用,发现和普通的二叉查找树没什么区别,只是用了splay操作节省了时间开支。

而Splay序列之王的称号可不是白给的。

Splay真正强大的地方是他的区间操作。

怎么实现呢?

我们知道查找树的中序遍历是一个有序的序列。这个时候我们打破查找树左小右大的规则,而是把他的中序遍历作为我们的区间进行维护。

具体来讲有以下操作:

1、建树

2、区间操作【翻转、赋值啊什么的】

3、输出序列

建树

既然是区间,我们可以借鉴线段树的建树
void build(int& u,int l,int r,int fa)
{
if(l>=r) return;
u=++siz;
int mid=(l+r)>>1;
e[u].v=mid;
e[u].siz=1;
e[u].f=fa;
if(l+1<r)
{
build(e[u].ch[0],l,mid,u);
build(e[u].ch[1],mid+1,r,u);
e[u].siz+=e[e[u].ch[0]].siz+e[e[u].ch[1]].siz;
}
}
就用递归从中间建起

区间操作

我们想要从树中找到我们需要的区间,怎么办呢?
这个时候就是发挥Splay威力的时候了> <
Splay的伸展操作【也就是splay操作】可以在不改变中序遍历的前提下改变树的结构,也就是说我们可以在不改变序列的前提下改变树的形态。
那么这个时候,如果我们要操作区间[l,r]我们只需将l-1翻转到根节点,将r+1翻转到根节点的右儿子
这个时候想想,r+1的左子树是什么?
没错!就是我们要的区间[l,r]
怎么找到这两个节点?
就套用splay中的查找第k大节点就好了【其实在这里不能说是第k大,是第k个】
但是我们如果要操作[1,N]怎么办?
我们加一个0和N+1节点不就好啦【哨兵】
至于找到区间后怎么操作,就因题而异啦,一般都会加上一个lazy标记节省时间
附上splay操作
#define isr(x) (e[e[x].f].ch[1]==x)

...........

inline void spin(int u)
{
int fa=e[u].f,s=isr(u);
e[u].f=e[fa].f;
if(e[fa].f) e[e[fa].f].ch[isr(fa)]=u;
e[fa].ch[s]=e[u].ch[s^1];
e[fa].f=u;
if(e[u].ch[s^1]) e[e[u].ch[s^1]].f=fa;
e[u].ch[s^1]=fa;
up(fa);up(u);
} void splay(int u,int fa=0)
{
while(e[u].f!=fa)
{
if(e[e[u].f].f&&lazy[e[e[u].f].f]) pd(e[e[u].f].f);
if(lazy[e[u].f]) pd(e[u].f);
if(lazy[u]) pd(u);
if(e[e[u].f].f==fa) spin(u);
else if(isr(u)^isr(e[u].f)) spin(u),spin(u);
else spin(e[u].f),spin(u);
}
if(!fa) root=u;
}
其中lazy是打的标记,splay的时候记得下传【凡是涉及到儿子的操作都要考虑标记下传】
pd是标记下传函数

输出序列

其实就是中序遍历嘛,自己打【其实是我懒】
来道裸题:
洛谷P3391 文艺平衡树
裸的区间翻转
#include<iostream>
#include<cstdio>
#include<algorithm>
#define isr(x) (e[e[x].f].ch[1]==x)
using namespace std;
const int maxn=200005,INF=2000000000;
int N,M; inline int read()
{
int out=0,flag=1;char c=getchar();
while(c<48||c>57) {if(c=='-') flag=-1;c=getchar();}
while(c>=48&&c<=57){out=out*10+c-48;c=getchar();}
return out*flag;
} int lazy[maxn]; class node
{
public:
int v,ch[2],f,siz;
node() {ch[0]=ch[1]=0;siz=0;}
}e[maxn];
int siz=0,root=0; inline void up(int u){e[u].siz=e[e[u].ch[0]].siz+e[e[u].ch[1]].siz+1;} inline void pd(int u)
{
swap(e[u].ch[0],e[u].ch[1]);
lazy[e[u].ch[0]]^=1;
lazy[e[u].ch[1]]^=1;
lazy[u]^=1;
} inline void spin(int u)
{
int fa=e[u].f,s=isr(u);
e[u].f=e[fa].f;
if(e[fa].f) e[e[fa].f].ch[isr(fa)]=u;
e[fa].ch[s]=e[u].ch[s^1];
e[fa].f=u;
if(e[u].ch[s^1]) e[e[u].ch[s^1]].f=fa;
e[u].ch[s^1]=fa;
up(fa);up(u);
} void splay(int u,int fa=0)
{
while(e[u].f!=fa)
{
if(e[e[u].f].f&&lazy[e[e[u].f].f]) pd(e[e[u].f].f);
if(lazy[e[u].f]) pd(e[u].f);
if(lazy[u]) pd(u);
if(e[e[u].f].f==fa) spin(u);
else if(isr(u)^isr(e[u].f)) spin(u),spin(u);
else spin(e[u].f),spin(u);
}
if(!fa) root=u;
} /*void insert(int& u,int v,int fa)
{
if(!u) {e[u=++siz].v=v;e[u].f=fa;splay(u);}
else if(e[u].v>v) insert(e[u].ch[0],v,u);
else insert(e[u].ch[1],v,u);
}*/ int kth(int u,int k)
{
if(lazy[u]) pd(u);
if(k==e[e[u].ch[0]].siz+1) {/*splay(u);*/return u;}
else if(k>e[e[u].ch[0]].siz+1) return kth(e[u].ch[1],k-e[e[u].ch[0]].siz-1);
return kth(e[u].ch[0],k);
} void change(int l,int r)
{
int L=kth(root,l),R=kth(root,r+2);
splay(L);
splay(R,root);
lazy[e[e[root].ch[1]].ch[0]]^=1;
} void build(int& u,int l,int r,int fa)
{
if(l>=r) return;
u=++siz;
int mid=(l+r)>>1;
e[u].v=mid;
e[u].siz=1;
e[u].f=fa;
if(l+1<r)
{
build(e[u].ch[0],l,mid,u);
build(e[u].ch[1],mid+1,r,u);
e[u].siz+=e[e[u].ch[0]].siz+e[e[u].ch[1]].siz;
}
} void print(int u)
{
if(u)
{
if(lazy[u]) pd(u);
print(e[u].ch[0]);
if(e[u].v>=1&&e[u].v<=N) printf("%d ",e[u].v);
print(e[u].ch[1]);
}
} int main()
{
N=read();
M=read();
int a,b;
build(root,0,N+2,0);
while(M--)
{
a=read();
b=read();
if(a==b) continue;
change(a,b);
/*print(root);
cout<<endl;*/
}
print(root);
cout<<endl;
//system("pause >nul");
return 0;
}

Splay 的区间操作的更多相关文章

  1. [AHOI2006]文本编辑器 Splay tree区间操作

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1269 Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个 ...

  2. 文艺平衡树-splay的区间操作

    真的是个神题,蒟蒻表示无力吐槽.刚开始以为是一个板子题,看着题解打了一遍,大概也理解了他是怎么实现的,然后我就去做别的题了,然后就在Three_D大佬的询问下蒙*了.最后还是问的nc哥,并思考了一个中 ...

  3. HDU 1754 I Hate It (Splay 区间操作)

    题目大意 维护一个序列,支持两种操作 操作一:将第x个元素的值修改为y 操作二:询问区间[x,y]内的元素的最大值 解题分析 splay的区间操作,事先加入两个编号最小和最大的点防止操作越界. 具体的 ...

  4. P2042 [NOI2005]维护数列 && Splay区间操作(四)

    到这里 \(A\) 了这题, \(Splay\) 就能算入好门了吧. 今天是个特殊的日子, \(NOI\) 出成绩, 大佬 \(Cu\) 不敢相信这一切这么快, 一下子机房就只剩我和 \(zrs\) ...

  5. P2596 [ZJOI2006]书架 && Splay 区间操作(三)

    P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...

  6. Splay 区间操作

    据大佬说,\(Splay\)是序列操作之王.\(Splay\)是一种平衡树,通过伸展(\(Splay\)),在不改变中序遍历的前提下变换根的位置,从而快速的进行序列操作 \(Splay\)最常见的序列 ...

  7. POJ-3468 A Simple Problem with Integers Splay Tree区间练习

    题目链接:http://poj.org/problem?id=3468 以前用线段树做过,现在用Splay Tree A了,向HH.kuangbin.cxlove大牛学习了各种Splay各种操作,,, ...

  8. Splay树简单操作

    前几天刚刚自学了一下splay,发现思路真简单实现起来好麻烦 先贴一下头文件 # include <stdio.h> # include <stdlib.h> # includ ...

  9. splay tree旋转操作 hdu 1890

    很神奇的旋转操作. 目前没看到其他数据结构能实现这个功能.平衡树不好处理区间操作,线段树很难旋转.splay tree搞这个就很简单了. 下面用的这个模板跑了700ms,好慢,估计是删除操作太费时了, ...

随机推荐

  1. 【MYSQL备份】利用mysqldump将一个数据库复制到另一个数据库

    假设要将服务器A上的数据库test备份到服务器B 1.在服务器B上新建数据库cp_test mysql> create database cp_test; Query OK, row affec ...

  2. 【Jmeter测试】使用Java请求进行Dubbo接口的测试

    如何构建一个Dubbo接口测试的通用框架(https://github.com/nitibu/jmeter-dubbo-test)​从上面的流程我们可以看出,测试类大致的一个结构: 使用json文件来 ...

  3. localhost/127.0.0.1/本机IP的区别以及端口号

    端口号: http请求默认的端口是:80 PHPstudy中的端口号: Apache服务器的端口是:80 MySQL数据库的端口是:3306 PHP项目端口是:9000 禅道中的端口号: Apache ...

  4. 利用xlsxwriter生成数据报表

    #!/usr/bin/env python# -*- coding:utf-8 -*-import os,xlsxwriter,datetimeimport ConfigParserfrom send ...

  5. 【C#】人脸识别 视频数据转图片数据

    使用虹软人脸识别的开发过程中遇到了转换的问题 因为不会用C#直接打开摄像头,就只能用第三方dll.一开始用Aforge,后来发现有个问题,关闭摄像头老是陷入等待,所以抛弃了.前一阵子开始用封装了Ope ...

  6. [shell] awk学习

    awk处理最后一行 awk '{if(NR>1)print a;a=$0}END{print a="b"}' file awk 'BEGIN{getline a}{print ...

  7. 你应该知道的PHP库

    Libchart – 这也是一个简单的统计图库. JpGraph – 一个面向对象的图片创建类. Open Flash Chart – 这是一个基于Flash的统计图. RSS 解析 解释RSS并是一 ...

  8. 20181120-8 Beta阶段第2周/共2周 Scrum立会报告+燃尽图 06

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2414 版本控制地址    [https://git.coding.net ...

  9. 20181113-7 Beta阶段第1周/共2周 Scrum立会报告+燃尽图 04

    作业要求:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2386] 版本控制:[https://git.coding.net/lglr2 ...

  10. 王者荣耀交流协会--第3次Scrum会议

    Scrum master:王玉玲 要求1:工作照片 要求2:时间跨度:2017年10月15号  6:00--6:24  共计24min要求3:地点:传媒西楼204,会议室要求4:立会内容:1.从昨日会 ...