伸展树Splay
新学的,其实吧,就那么回事....
看了几天,splay处理序列问题,真的非常厉害,翻转,插入,删除,线段树实现不了的功能,splay用起来很方便。
这题基本就是检验模板的题,各种操作都有,错了好多次,发现以前写的代码有错了的,数据水点,给水过了,注意pushup。
Splay模板
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;
#define N 500000
#define INF 0x7FFFFFFF
#define keyTree (ch[ ch[root][1] ][0])
int pre[N];
int lz[N];
int rev[N];
int ch[N][];
int val[N];
int minz[N];
int sz[N];
int num[N];
int root,t;
void pushup(int x)
{
minz[x] = min(val[x],min(minz[ch[x][]],minz[ch[x][]]));
sz[x] = sz[ch[x][]] + sz[ch[x][]] + ;
}
void Update_Rev(int x)
{
if(!x) return ;
swap(ch[x][],ch[x][]);
rev[x] ^= ;
}
void Update_Add(int x,int d)
{
if(!x) return ;
val[x] += d;
minz[x] += d;
lz[x] += d;
}
void pushdown(int x)
{
if(lz[x])
{
Update_Add(ch[x][],lz[x]);
Update_Add(ch[x][],lz[x]);
lz[x] = ;
}
if(rev[x])
{
Update_Rev(ch[x][]);
Update_Rev(ch[x][]);
rev[x] = ;
}
}
void NewNode(int &x,int c)
{
x = ++t;
ch[x][] = ch[x][] = ;
sz[x] = ;
lz[x] = rev[x] = ;
minz[x] = val[x] = c;
}
void makeTree(int &x,int l,int r,int rt)
{
if(l > r) return ;
int m;
m = (l + r)>>;
NewNode(x,num[m]);
makeTree(ch[x][],l,m-,x);
makeTree(ch[x][],m+,r,x);
pre[x] = rt;
pushup(x);
}
void Rotate(int x,int flag)//左旋 右旋
{
int y = pre[x];
pushdown(y);
pushdown(x);
ch[y][!flag] = ch[x][flag];
pre[ch[x][flag]] = y;
pre[x] = pre[y];
if(pre[x])
ch[pre[y]][ ch[pre[y]][] == y] = x;
ch[x][flag] = y;
pre[y] = x;
pushup(y);
}
void splay(int x,int goal)//把x转到goal下面
{
int y,z,flag;
while(pre[x] != goal)
{
if(pre[pre[x]] == goal)
{
pushdown(pre[x]);
pushdown(x);
Rotate(x,ch[pre[x]][] == x);
}
else
{
y = pre[x];
z = pre[y];
pushdown(z);
pushdown(y);
pushdown(x);
flag = (ch[z][] == y);
if(ch[y][flag] == x)
{
Rotate(x,!flag);
Rotate(x,flag);
}
else
{
Rotate(y,flag);
Rotate(x,flag);
}
}
}
pushup(x);
if(goal == ) root = x;
}
void RotateTo(int k,int goal)//将第k个,转到goal下面
{
int x = root;
pushdown(x);
while(sz[ch[x][]] != k)
{
if(k < sz[ch[x][]])
{
x = ch[x][];
}
else
{
k -= (sz[ch[x][]] + );
x = ch[x][];
}
pushdown(x);
}
splay(x,goal);
}
void init(int n)
{
root = t = ;
ch[][] = ch[][] = lz[] = pre[] = ;
val[] = minz[] = ;
rev[] = sz[] = ;//初始化
NewNode(root,-);
NewNode(ch[root][],-);
pre[t] = root;
int i;
for(i = ; i < n; i ++)
{
scanf("%d",&num[i]);
}
makeTree(keyTree,,n-,ch[root][]);//建树
pushup(ch[root][]);
pushup(root);
}
int main()
{
int n,i,x,y,d,m;
char str[];
scanf("%d",&n);
init(n);
scanf("%d",&m);
for(i = ; i < m; i ++)
{
scanf("%s",str);
if(strcmp(str,"ADD") == )
{
scanf("%d%d%d",&x,&y,&d);
RotateTo(x-,);
RotateTo(y+,root);
Update_Add(keyTree,d);
pushup(ch[root][]);
pushup(root);
}
else if(strcmp(str,"INSERT") == )//插入
{
scanf("%d%d",&x,&y);
RotateTo(x,);
RotateTo(x+,root);
NewNode(keyTree,y);
pre[keyTree] = ch[root][];
pushup(ch[root][]);
pushup(root);
}
else if(strcmp(str,"DELETE") == )//删除
{
scanf("%d",&x);
RotateTo(x-,);
RotateTo(x+,root);
pre[keyTree] = ;
keyTree = ;
pushup(ch[root][]);
pushup(root);
}
else if(strcmp(str,"MIN") == )//最值
{
scanf("%d%d",&x,&y);
RotateTo(x-,);
RotateTo(y+,root);
printf("%d\n",minz[keyTree]);
}
else if(strcmp(str,"REVOLVE") == )//右移t位
{
int t,temp;
scanf("%d%d%d",&x,&y,&t);
if(x > y) swap(x,y);
t = t%(y-x+);
if(t < ) t += (y-x+);
if(t == ) continue;
RotateTo(y-t,);
RotateTo(y+,root);
temp = keyTree;
keyTree = ;
RotateTo(x-,);
RotateTo(x,root);
keyTree = temp;
pre[keyTree] = ch[root][];
pushup(ch[root][]);
pushup(root);
}
else
{
scanf("%d%d",&x,&y);//翻转区间
if(x > y) swap(x,y);
RotateTo(x-,);
RotateTo(y+,root);
Update_Rev(keyTree);
pushup(ch[root][]);
pushup(root);
}
}
return ;
}
这题是现场赛的题目啊...非常麻烦,不过想好了,就没什么了,主要是翻转哪里。
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;
#define N 300000
#define INF 0x7FFFFFFF
#define keyTree (ch[ ch[root][1] ][0])
int ch[N][];
int pre[N];
int val[N];
int lz[N];
int sz[N];
int rev[N];
int num[N];
int root,t;
void Update_Add(int x,int d)
{
if(!x) return ;
lz[x] += d;
val[x] += d;
}
void Update_Rev(int x)
{
if(!x) return ;
swap(ch[x][],ch[x][]);
rev[x] ^= ;
}
void pushdown(int x)
{
if(lz[x])
{
Update_Add(ch[x][],lz[x]);
Update_Add(ch[x][],lz[x]);
lz[x] = ;
}
if(rev[x])
{
Update_Rev(ch[x][]);
Update_Rev(ch[x][]);
rev[x] = ;
}
}
void pushup(int x)
{
sz[x] = sz[ch[x][]] + sz[ch[x][]] + ;
}
void NewNode(int &x,int c,int fa)
{
x = ++t;
ch[x][] = ch[x][] = ;
lz[x] = rev[x] = ;
sz[x] = ;
val[x] = c;
pre[x] = fa;
}
void makeTree(int &x,int l,int r,int rt)
{
if(l > r) return ;
int m = (l + r)>>;
NewNode(x,num[m],rt);
makeTree(ch[x][],l,m-,x);
makeTree(ch[x][],m+,r,x);
pushup(x);
}
void Rotate(int x,int flag)
{
int y = pre[x];
pushdown(y);
pushdown(x);
ch[y][!flag] = ch[x][flag];
pre[ch[x][flag]] = y;
pre[x] = pre[y];
if(pre[x])
ch[pre[y]][ ch[pre[y]][] == y ] = x;
ch[x][flag] = y;
pre[y] = x;
pushup(y);
}
void splay(int x,int goal)
{
int y,z,flag;
while(pre[x] != goal)
{
if(pre[pre[x]] == goal)
{
pushdown(pre[x]);
pushdown(x);
Rotate(x,ch[pre[x]][] == x);
}
else
{
y = pre[x];
z = pre[y];
pushdown(z);
pushdown(y);
pushdown(x);
flag = (ch[z][] == y);
if(ch[y][flag] == x)
{
Rotate(x,!flag);
Rotate(x,flag);
}
else
{
Rotate(y,flag);
Rotate(x,flag);
}
}
}
pushup(x);
if(goal == ) root = x;
}
void RotateTo(int k,int goal)
{
int x = root;
pushdown(x);
while(sz[ch[x][]] != k)
{
if(k < sz[ch[x][]])
{
x = ch[x][];
}
else
{
k -= (sz[ch[x][]] + );
x = ch[x][];
}
pushdown(x);
}
splay(x,goal);
}
int get_kth(int k)
{
int x = root;
pushdown(x);
while(sz[ch[x][]] != k)
{
if(k < sz[ch[x][]])
{
x = ch[x][];
}
else
{
k -= (sz[ch[x][]] + );
x = ch[x][];
}
pushdown(x);
}
return val[x];
}
void show(int x)
{
if(x == ) return ;
pushdown(x);
show(ch[x][]);
if(val[x] > )
{
printf("%d ",val[x]);
}
show(ch[x][]);
}
int main()
{
int i,k1,k2,n,m,pos,x,y,d,cas = ;
char str[];
while(scanf("%d%d%d%d",&n,&m,&k1,&k2)!=EOF)
{
if(n == &&m == ) break;
root = t = ;
ch[][] = ch[][] = sz[] = pre[] = ;
rev[] = lz[] = ;
NewNode(root,-,);
NewNode(ch[root][],-,root);
for(i = ;i < n;i ++)
scanf("%d",&num[i]);
makeTree(keyTree,,n-,ch[root][]);
pushup(ch[root][]);
pushup(root);
pos = ;
printf("Case #%d:\n",cas++);
for(i = ;i < m;i ++)
{
scanf("%s",str);
if(str[] == 'a')
{
scanf("%d",&d);
x = pos;
y = pos + k2 -;
if(y <= n)
{
RotateTo(x-,);
RotateTo(y+,root);
Update_Add(keyTree,d);
pushup(ch[root][]);
pushup(root);
}
else
{
RotateTo(x-,);
RotateTo(n+,root);
Update_Add(keyTree,d);
pushup(ch[root][]);
pushup(root); RotateTo(,);
RotateTo(y-n+,root);
Update_Add(keyTree,d);
pushup(ch[root][]);
pushup(root);
}
}
else if(str[] == 'r')
{
x = pos;
y = pos + k1 - ;
if(y <= n)
{
RotateTo(x-,);
RotateTo(y+,root);
Update_Rev(keyTree);
}
else
{
int tb = n-x+;
int ta = k1 - tb; RotateTo(x-,);
RotateTo(n+,root);
Update_Rev(keyTree);
pushup(ch[root][]);
pushup(root); RotateTo(,);
RotateTo(ta+,root);
Update_Rev(keyTree);
int temp = keyTree;
keyTree = ;
pushup(ch[root][]);
pushup(root); RotateTo(x--ta,);
RotateTo(x-ta,root);
keyTree = temp;
pre[keyTree] = ch[root][];
pushup(ch[root][]);
pushup(root); RotateTo(n-ta,);
RotateTo(n+,root);
temp = keyTree;
keyTree = ;
pushup(ch[root][]);
pushup(root); RotateTo(,);
RotateTo(,root);
keyTree = temp;
pre[keyTree] = ch[root][];
pushup(ch[root][]);
pushup(root);
}
}
else if(str[] == 'i')
{
n ++;
scanf("%d",&d);
x = pos;
RotateTo(x,);
RotateTo(x+,root);
NewNode(keyTree,d,ch[root][]);
pushup(ch[root][]);
pushup(root);
}
else if(str[] == 'd')
{ x = pos;
RotateTo(x-,);
RotateTo(x+,root);
keyTree = ;
pushup(ch[root][]);
pushup(root);
if(pos == n) pos = ;
n --;
}
else if(str[] == 'm')
{
scanf("%d",&d);
if(d == )
{
pos ++;
if(pos > n) pos = ;
}
else
{
pos --;
if(pos == ) pos = n;
}
}
else
{
printf("%d\n",get_kth(pos));
}
}
}
return ;
}
/*
5 100 3 2
1 2 3 4 5
m 2
m 2
m 2
reverse
*/
伸展树Splay的更多相关文章
- 树-伸展树(Splay Tree)
伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...
- 纸上谈兵: 伸展树 (splay tree)[转]
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每 ...
- K:伸展树(splay tree)
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...
- 高级搜索树-伸展树(Splay Tree)
目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...
- 【BBST 之伸展树 (Splay Tree)】
最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...
- [Splay伸展树]splay树入门级教程
首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...
- 伸展树Splay【非指针版】
·伸展树有以下基本操作(基于一道强大模板题:codevs维护队列): a[]读入的数组;id[]表示当前数组中的元素在树中节点的临时标号;fa[]当前节点的父节点的编号;c[][]类似于Trie,就是 ...
- 伸展树(Splay tree)的基本操作与应用
伸展树的基本操作与应用 [伸展树的基本操作] 伸展树是二叉查找树的一种改进,与二叉查找树一样,伸展树也具有有序性.即伸展树中的每一个节点 x 都满足:该节点左子树中的每一个元素都小于 x,而其右子树中 ...
- ZOJ 3765 Lights (zju March I)伸展树Splay
ZJU 三月月赛题,当时见这个题目没辙,没学过splay,敲了个链表TLE了,所以回来好好学了下Splay,这道题目是伸展树的第二题,对于伸展树的各项操作有了更多的理解,这题不同于上一题的用指针表示整 ...
- [数据结构]伸展树(Splay)
#0.0 写在前面 Splay(伸展树)是较为重要的一种平衡树,理解起来也依旧很容易,但是细节是真的多QnQ,学一次忘一次,还是得用博客加深一下理解( #1.0 Splay! #1.1 基本构架 Sp ...
随机推荐
- [转] Unity Mathf 数学运算(C#)
Mathf.Abs 绝对值 计算并返回指定参数 f 绝对值. Mathf.Acos 反余弦 static function Acos (f : float) : float 以弧度为单位计算并返回参数 ...
- spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler)
spring 封装了非常强大的异常处理机制.本文选取@ControllerAdvice + @ExceptionHandler 这种零配置(全注解),作为异常处理解决方案! @ControllerAd ...
- [Machine Learning] 国外程序员整理的机器学习资源大全
本文汇编了一些机器学习领域的框架.库以及软件(按编程语言排序). 1. C++ 1.1 计算机视觉 CCV —基于C语言/提供缓存/核心的机器视觉库,新颖的机器视觉库 OpenCV—它提供C++, C ...
- 使用Entity Framework通过code first方式创建数据库和数据表
开发环境 WIN10 Entity Framework6.0 MVC5.0 开发工具 VS2015 SqlServer2012 1.创建上下文Context继承DbContext,并创建其他的业 ...
- 检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(转)
我们将ASP.NET程序从IIS6移植到IIS7,可能运行提示以下错误: HTTP 错误 500.23 - Internal Server Error 检测到在集成的托管管道模式下不适用的 ASP.N ...
- Spring Data JPA @EnableJpaRepositories配置详解
@EnableJpaRepositories注解用于Srping JPA的代码配置,用于取代xml形式的配置文件,@EnableJpaRepositories支持的配置形式丰富多用,本篇文章详细讲解. ...
- 使用jvisualvm.exe 的Btrace插件介绍/使用教程
一.背景 在生产环境中可能经常遇到各种问题,定位问题需要获取程序运行时的数据信息,如方法参数.返回值.全局变量.堆栈信息等.为了获取这些数据信息,我们可以 通过改写代码,增加日志信息的打 ...
- 去哪儿网输入框三种输入方式(selenium webdriver 干货)
在机票预定的页面,输入出发城市和到达城市输入框的时候, 发现直接使用sendkeys不好使, 大部分情况出现输入某城市后没有输入进去, 经过几天的研究,发现可以采取三种方式: 1. 先点击输入框,待弹 ...
- QQ付费群规则重大变更!特别是这类群!
很多人都是知道现在QQ有个付费群功能.以往加群需要你填写一些验证信息给管理员,管理员看你顺眼就放你进去,不顺眼你就进不去了.另外还有一些打广告的人难免会被管理员误判给放进去,令管理员苦恼不已,总有审核 ...
- 解决log4j:WARN No appenders could be found for logger
这个问题是因为我们的log4j.properties文件配置不够完整,所以我们给它配置齐了就不会再出现这个问题. log4j.properties不完整配置如下: log4j.rootLogger=D ...