Splay 的区间操作
学完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;
}
}
区间操作
#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;
}
输出序列
#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 的区间操作的更多相关文章
- [AHOI2006]文本编辑器 Splay tree区间操作
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1269 Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个 ...
- 文艺平衡树-splay的区间操作
真的是个神题,蒟蒻表示无力吐槽.刚开始以为是一个板子题,看着题解打了一遍,大概也理解了他是怎么实现的,然后我就去做别的题了,然后就在Three_D大佬的询问下蒙*了.最后还是问的nc哥,并思考了一个中 ...
- HDU 1754 I Hate It (Splay 区间操作)
题目大意 维护一个序列,支持两种操作 操作一:将第x个元素的值修改为y 操作二:询问区间[x,y]内的元素的最大值 解题分析 splay的区间操作,事先加入两个编号最小和最大的点防止操作越界. 具体的 ...
- P2042 [NOI2005]维护数列 && Splay区间操作(四)
到这里 \(A\) 了这题, \(Splay\) 就能算入好门了吧. 今天是个特殊的日子, \(NOI\) 出成绩, 大佬 \(Cu\) 不敢相信这一切这么快, 一下子机房就只剩我和 \(zrs\) ...
- P2596 [ZJOI2006]书架 && Splay 区间操作(三)
P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...
- Splay 区间操作
据大佬说,\(Splay\)是序列操作之王.\(Splay\)是一种平衡树,通过伸展(\(Splay\)),在不改变中序遍历的前提下变换根的位置,从而快速的进行序列操作 \(Splay\)最常见的序列 ...
- POJ-3468 A Simple Problem with Integers Splay Tree区间练习
题目链接:http://poj.org/problem?id=3468 以前用线段树做过,现在用Splay Tree A了,向HH.kuangbin.cxlove大牛学习了各种Splay各种操作,,, ...
- Splay树简单操作
前几天刚刚自学了一下splay,发现思路真简单实现起来好麻烦 先贴一下头文件 # include <stdio.h> # include <stdlib.h> # includ ...
- splay tree旋转操作 hdu 1890
很神奇的旋转操作. 目前没看到其他数据结构能实现这个功能.平衡树不好处理区间操作,线段树很难旋转.splay tree搞这个就很简单了. 下面用的这个模板跑了700ms,好慢,估计是删除操作太费时了, ...
随机推荐
- JavaWeb(十三)——使用Session防止表单重复提交
在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...
- 使用Python的Requests库进行web接口测试
1.Requests简介Requests 是使用 Apache2 Licensed 许可证的 HTTP 库.用 Python 编写,真正的为人类着想. Python 标准库中的 urllib2 模块提 ...
- mnist手写数字识别(Logistic回归)
import numpy as np from sklearn.neural_network import MLPClassifier from sklearn.linear_model import ...
- C++11的左值引用与右值引用总结
概念 在C++11中,区别表达式是左值或右值可以做这样的总结:当一个对象被用作右值的时候,用的是对象的值(内容):当对象被用作左值的时候,用的是对象的身份(在内存中的位置).左值有持久的状态,而右值要 ...
- CsvHelper文档-6类型转换
CsvHelper文档-6类型转换 CsvHelper使用类型转换器来转换string到对象,或者对象到string: ITypeConverter 类型转换器的结构,必须实现: public int ...
- day02——作业讲解
# 设定⼀个理想数字⽐如:66,让⽤户输⼊数字,如果⽐66⼤,则显示猜测# 的结果⼤了:如果⽐66⼩,则显示猜测的结果⼩了;只有等于66,显示猜测结果# 正确,然后退出循环 #升级版# 可以帮我们生成 ...
- Java接口interface,匿名内部类
接口 1.接口内部为 常量+公用的抽象方法.类必须实现接口中的所有方法 2.接口的语法格式:不写abstract会自动添加,可以继承多个接口 修饰符不能使private,protected [修饰符] ...
- 周总结<4>
经过了一周的学习,我们在html以及C语言方面又有的新的知识点的学习. html 自习表格,函数等 C语言 哈弗曼编码 Html案例: 一. <!DOCTYPE html PUBLIC &quo ...
- 第四章 深入JSP技术
JSP简介 JSP工作原理 JSP是一种servlet,但先部署后编译. JSP生命周期 运行时只会有一个实例,同servlet. JSP语法 JSP元素和模板数据 模板数据就是JSP中的HTML代码 ...
- phpdisk 盲注 &前台任意用户登录
代码审核 文件 plugins\phpdisk_client\passport.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $str ...