[洛谷P3391] 文艺平衡树 (Splay模板)
初识splay
学splay有一段时间了,一直没写......
本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列。
模板题嘛......主要了解一下splay的基本操作QwQ
1.基本概念
splay是一种二叉搜索树,节点的权值满足lson<p<rson,故可以像其他二叉搜索树一样在树上二分查找某数排名,排名为k的数,以及前驱后继等。
普通的二叉搜索树在面对特殊数据时树的深度会从log n退化成接近n(退化成链),这样操作的时间复杂度会从O(log n)退化成O(n),影响效率。
splay通过旋转维持树的平衡。这个操作后面会提到。
2.基本操作
二叉搜索树的基本操作:求排名为k的数。
int rank(int p,int k)
{
pushdown(p);
if(k<=sz[s[p][]])
return rank(s[p][],k);
else if(k==sz[s[p][]]+)
return p;
else
return rank(s[p][],k-sz[s[p][]]-);
}
简单的树上二分。
3.核心操作:splay
splay的精髓在于骚气的旋转。(名字就是这么来的哈哈哈~)
splay的核心操作是splay(一脸懵逼),splay(x,y)意为通过一系列旋转,将点x旋转到点y下面,使x成为y的儿子。
每次旋转通过rotate函数实现:
void rotate(int p)
{
int fa=f[p];
bool k=id(p);
s[fa][k]=s[p][!k];
s[p][!k]=fa;
s[f[fa]][id(fa)]=p;
f[p]=f[fa];
f[s[fa][k]]=fa;
f[fa]=p;
refresh(fa);
refresh(p);
}
rotate的时候严格满足splay二叉搜索树的性质:lson<p<rson。
将p提到fa的位置,根据大小关系决定fa是作为p的左儿子还是右儿子,这样实际上是fa挤掉了p原先的某个儿子,而p转上去,让出了fa的一个儿子的位置。
所以最后让那个被fa挤掉的p的孤儿作为fa的某个儿子,填到空缺的地方去(原来p的位置)。
至于splay的实现方法...有两种:单旋和双旋。
单旋即无脑地一直转,直到把x转到y下面。
void splay(int p,int g) // 单旋
{
while(f[p]!=g)rotate(p);
if(!g)root=p;
}
比起单旋,双旋能更好的维护splay的平衡。
void splay(int p,int g) // 双旋
{
while(f[p]!=g)
{
int fa=f[p];
if(f[fa]==g)
{
rotate(p);
break;
}
if(id(p)^id(fa))rotate(p);
else rotate(fa);
rotate(p);
}
if(!g)root=p;
}
利用splay操作,我们就可以用这棵树实现很多其它平衡树实现不了的功能。
4.元素的插入、删除、查询及修改
设x为 要插入的/要删除的/要查询的/要修改的 元素or区间。
进行这些操作之前,运用旋转操作把x的前驱pre转到根位置,把x的后继post转到根的下面,post>pre,所以此时post一定是pre的右儿子。
(如果是区间,pre就是left的前驱,post就是right的后继)
如图:

此时,根据二叉搜索树的性质,要删除/查询/修改的元素or区间就一定在post的左子树那里。如图:(目标子树:红色部分)

4.1 插入
如果是插入,红色部分一定为空,在那里插入即可。
4.2 删除
残忍抛弃红色部分。
4.3 查询
在红色部分查询。
4.4 修改
在这道题里是区间翻转。
我们并不需要真的翻转,打个标记就行。
标记需要下传的时候,交换左右子树的左右子树,在左右儿子上打标记,清掉自身标记。
void pushdown(int p)
{
if(!fl[p])return;
fl[s[p][]]^=;
fl[s[p][]]^=;
swap(s[s[p][]][],s[s[p][]][]);
swap(s[s[p][]][],s[s[p][]][]);
fl[p]=;
}
这样就行了。
完事了?
完事了。
最后二分输出序列即可。
其他细节见代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define id(x) (s[f[x]][1]==x) // 判断是左儿子还是右儿子
using namespace std; int f[N],s[N][],val[N],sz[N],root,tot; // 分别是父亲,儿子,值,子树大小,树根,元素数量
bool fl[N]; // 翻转标记 void refresh(int p) // 更新size
{
sz[p]=sz[s[p][]]+sz[s[p][]]+;
} void pushdown(int p) // 下传标记
{
if(!fl[p])return;
fl[s[p][]]^=;
fl[s[p][]]^=;
swap(s[s[p][]][],s[s[p][]][]);
swap(s[s[p][]][],s[s[p][]][]);
fl[p]=;
} void rotate(int p) // 把p转上去
{
int fa=f[p];
bool k=id(p);
s[fa][k]=s[p][!k];
s[p][!k]=fa;
s[f[fa]][id(fa)]=p;
f[p]=f[fa];
f[s[fa][k]]=fa;
f[fa]=p;
refresh(fa);
refresh(p);
}
/*
void splay(int p,int g) // 单旋
{
while(f[p]!=g)rotate(p);
if(!g)root=p;
}
*/
void splay(int p,int g) // 双旋
{
while(f[p]!=g)
{
int fa=f[p];
if(f[fa]==g)
{
rotate(p);
break;
}
if(id(p)^id(fa))rotate(p);
else rotate(fa);
rotate(p);
}
if(!g)root=p;
} int rank(int p,int k) // 查询rank为k的元素
{
pushdown(p);
if(k<=sz[s[p][]])
return rank(s[p][],k);
else if(k==sz[s[p][]]+)
return p;
else
return rank(s[p][],k-sz[s[p][]]-);
} int build(int l,int r,int fa) // 建树 实际上一个一个插入也行,但是这样二分建树可以使初始树更平衡
{
if(l>r)return ;
int mid=(l+r)>>;
int p=++tot;
s[p][]=build(l,mid-,p);
s[p][]=build(mid+,r,p);
val[p]=mid;
f[p]=fa;
refresh(p);
return p;
} void change(int l,int r) // 区间翻转
{
int pre,post,rt;
pre=rank(root,l-);
splay(pre,);
post=rank(root,r+);
splay(post,pre);
rt=s[post][];
swap(s[rt][],s[rt][]);
fl[rt]^=;
} void print(int p) // 二分输出结果序列
{
if(!p)return;
pushdown(p);
print(s[p][]);
printf("%d ",val[p]);
print(s[p][]);
} int n,m; int main()
{
scanf("%d%d",&n,&m);
root=build(,n+,);
for(int i=;i<=m;i++)
{
int lb,rb;
scanf("%d%d",&lb,&rb);
change(lb+,rb+);
}
splay(rank(root,),);
splay(rank(root,n+),root);
print(s[s[root][]][]);
return ;
} complete code of splay tree
complete code of splay tree

[洛谷P3391] 文艺平衡树 (Splay模板)的更多相关文章
- 洛谷P3391文艺平衡树(Splay)
题目传送门 转载自https://www.cnblogs.com/yousiki/p/6147455.html,转载请注明出处 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 ...
- BZOJ3223/洛谷P3391 - 文艺平衡树
BZOJ链接 洛谷链接 题意 模板题啦~2 代码 //文艺平衡树 #include <cstdio> #include <algorithm> using namespace ...
- BZOJ3224/洛谷P3391 - 普通平衡树(Splay)
BZOJ链接 洛谷链接 题意简述 模板题啦~ 代码 //普通平衡树(Splay) #include <cstdio> int const N=1e5+10; int rt,ndCnt; i ...
- 洛谷 P3391 文艺平衡树
题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 --b ...
- 洛谷P3391 文艺平衡树 (Splay模板)
模板题. 注意标记即可,另外,涉及区间翻转操作,记得设立首尾哨兵. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int ...
- 洛谷.3391.文艺平衡树(fhq Traep)
题目链接 //注意反转时先分裂r,因为l,r是针对整棵树的排名 #include<cstdio> #include<cctype> #include<algorithm& ...
- 洛谷 P3391 【模板】文艺平衡树(Splay)
题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1, ...
- 【阶梯报告】洛谷P3391【模板】文艺平衡树 splay
[阶梯报告]洛谷P3391[模板]文艺平衡树 splay 题目链接在这里[链接](https://www.luogu.org/problemnew/show/P3391)最近在学习splay,终于做对 ...
- luoguP3391[模板]文艺平衡树(Splay) 题解
链接一下题目:luoguP3391[模板]文艺平衡树(Splay) 平衡树解析 这里的Splay维护的显然不再是权值排序 现在按照的是序列中的编号排序(不过在这道题目里面就是权值诶...) 那么,继续 ...
随机推荐
- POJ-1015 Jury Compromise(dp|01背包)
题目: In Frobnia, a far-away country, the verdicts in court trials are determined by a jury consisting ...
- IT架构的本质--阅读笔记01
万物都有其本质,也只有了解了事物的本质之后,才不至于出现在事物稍作改变时就难以应对的情况,作为软件工程专业的学生,我们应该对IT架构的本质有一定的了解.“老僧三十年前未参禅时,见山是山,见水是水.及至 ...
- miniconda安装jupyter
1.安装jupyter 由于miniconda是anaconda的简化版,只有一个prompt: 安装jupyter,只需要打开prompt的dos窗口,输入命令pip install jupyter ...
- altium designer 画板 电子元器件的名称不能集体修改
今天在画板子的时候,遇到一个问题,就是发现电子元器件的名字太大了,想把他们集体都改小一点,方便布局,结果修改的时候却发现高度可以改,宽度改不了,(集体改的话,改不了,但是可以单独改,只是单独改,工程量 ...
- java select单线程 服务器
package com.Select; /** *select单线程 服务器 **/ import java.io.IOException; import java.net.InetSocketAdd ...
- 使用node 做静态文件服务器
# 1. 使用server-static 包 使用node可以非常快速的方法把指定目录共享出去 前提条件:安装了node,附带有npm 要托管的文件目录为 /root/www # 先创建一个目录用来存 ...
- java threadlocal 背景 本质
背景 JAVA中有全局变量(静态变量,不论在哪个函数 都能访问).局部变量(函数中定义的变量,在栈中,只能在本函数内访问),主要这2种类型. threadlocal变量 是一种线程级全局的变量(普通的 ...
- 写入简单的日志log
log.c: #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h& ...
- 八、linux-mysql的mysql主从复制原理和实战
1.mysql主从复制介绍 mysql支持单向.双向.链式级联.实时.异步复制,在复制过程中,一台服务器充当主服务器(Master),而一个或多个其它服务器充当从服务器(Slave). 复制:单向同步 ...
- [LC] 314. Binary Tree Vertical Order Traversal
Given a binary tree, return the vertical order traversal of its nodes' values. (ie, from top to bott ...