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,好慢,估计是删除操作太费时了, ...
随机推荐
- 手撕一个 Galgame 神器——Shub-Niggurath Project
一.想法 Galgame 我们大概可以分为好用的 Galgame 和好玩的 Galgame,但是如果你把好玩的 Galgame 拿来用的话,有时候会十分让人着急.如果你躺在床上,一只手还在按压键盘实际 ...
- Maven学习(七)-----Maven添加远程仓库
Maven添加远程仓库 默认情况下,Maven从Maven中央仓库下载所有依赖关系.但是,有些库丢失在中央存储库,只有在Java.net或JBoss的储存库远程仓库中能找到. 1. Java.net资 ...
- Django——POST请求及Action触发事件
添加网页login,将类型置为post,并添加action page,也就是之前写好的页面 添加page网页的views函数,要求获取post指令,如果username及password均正确则跳转到 ...
- 第k小分数(二分值)
//时间限制:10000ms //单点时限:1000ms //内存限制:256MB //描述 //给定N个不同的质数P1, P2, … PN.用它们作为分目可以组成(P1-1) + (P2-1) + ...
- Linux内核学习笔记(5)-- 进程调度概述
进程调度程序是多任务操作系统的基础,它是确保进程能有效工作的一个内核子系统,负责决定哪个进程投入运行.何时运行以及运行多长时间.只有通过进程调度程序的合理调度,系统资源才能够最大限度地发挥作用,多进程 ...
- JAVA学习笔记--策略设计模式与适配器模式
一.策略设计模式 创建一个能够根据所传递对象的不同而具有不同行为的方法被称为策略设计模式:这类方法包含所要执行的算法中固定不变的部分,而“策略”包含变化的部分.策略就是传递进去的参数对象,它包含要执行 ...
- 从零开始的Python学习Episode 8——深浅拷贝
深浅拷贝 一.浅拷贝 列表中存储的是数据的内存地址,当我们要查询或修改列表中的数据时,我们是通过列表中的地址找到要访问的内存.当我们修改列表中的数据时,如果修改的是一个不可变类型(整型,长整型,浮点数 ...
- LeetCode-124.二叉树中的最大路径和
给定一个非空二叉树,返回其最大路径和. 本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列.该路径至少包含一个节点,且不一定经过根节点. 示例 1: 输入: [1,2,3] 1 / \ 2 ...
- 75.[LeetCode] Sort Colors
Given an array with n objects colored red, white or blue, sort them in-place so that objects of the ...
- Seven super tips for successful selling on Amazon
Check for orders daily: To ship quickly you need to find out about orders promptly. We will e-mail y ...