一、题目

UVA11922

二、分析

为什么会有伸展树?

伸展树与AVL的区别除了保持平衡的方式不同外,最重要的是在每次查找点时,让该点旋转到根结点,这里可以结合计算机里的局部性原理思考。

伸展树有什么优势?

有了伸展树,我们可以根据每次到根节点的值,根据二叉搜索树的性质,可以将整棵树划分成两个部分,左子树的值都比根结点值大,右子树的值都比根结点小。

该题除了伸展树还用到了什么?

该题还需要旋转,所以,需要像线段树的lazy标记一样标记是否需要旋转。

有什么需要注意的地方?

一定注意写法的不同,构建树的范围不同,如果没有定于null数组,则需要将建树范围从$[1,n]$扩为$[0,n]$,因为空指针的sum(表示以该结点为根的树的大小)是不清楚的。

三、AC代码

 #include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; struct Node
{
Node *ch[];
int sum, val;
int flip;
Node(int v = )
{
val = v;
sum = ;
flip = ;
ch[] = ch[] = NULL;
}
int cmp(int x)
{
int d = x - (ch[] == NULL ? : ch[]->sum);
if(d == ) return -;
else return d <= ? : ;
}
void maintain()
{
sum = ;
if(ch[] != NULL) sum += ch[]->sum;
if(ch[] != NULL) sum += ch[]->sum;
}
void pushdown()
{
if(flip)
{
flip = ;
swap(ch[], ch[]); //**
if(ch[] != NULL)
ch[]->flip = !ch[]->flip;
if(ch[] != NULL)
ch[]->flip = !ch[]->flip;
}
}
}; void build(Node* &o, int l, int r)
{
if(l > r)
return;
int mid = (l + r) >> ;
o = new Node(mid);
build(o->ch[], l, mid - );
build(o->ch[], mid + , r);
o->maintain();
} void rotate(Node* &o, int d)
{
Node *k = o->ch[d^];
o->ch[d^] = k->ch[d];
k->ch[d] = o;
o->maintain();
k->maintain();
o = k;
} void splay(Node* &o, int k)
{
o->pushdown();
int d = o->cmp(k);
if(d == )
k -= (o->ch[] == NULL ? : o->ch[]->sum) + ;
//当前结点不是第k个,则需要往上伸展
if(d != -)
{
Node *p = o->ch[d];
p->pushdown(); int d2 = p->cmp(k);
int k2 = (d2 == ? k : k - (p->ch[] == NULL ? :p->ch[]->sum) - );
if(d2 != -)
{
splay(p->ch[d2], k2);
//x,x的父节点,x祖父结点三点共线
if(d == d2) rotate(o, d^);
//不共线
else rotate(o->ch[d], d);
}
rotate(o, d^);
}
} void print(Node* &o) //一定要传引用
{
o->pushdown();
if(o->ch[] != NULL) print(o->ch[]);
if(o->val)
printf("%d\n", o->val);
if(o->ch[] != NULL) print(o->ch[]); delete o;
o = NULL;
} Node* merge(Node* left, Node* right)
{
//left不能为NULL
//因为初始化了sum为1,对于空指针的sum,不清楚大小
//如何避免:建树从0开始,即保证sum>0
splay(left, left->sum);
left->ch[] = right;
left->maintain();
return left;
} void split(Node *o, int k, Node* &left, Node* &right)
{
splay(o, k);
left = o;
right = o->ch[];
o->ch[] = NULL;
left->maintain();
} int main()
{
//freopen("input.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
int N, M, a, b;
while(scanf("%d %d", &N, &M)==)
{
Node *root = NULL;
Node *left, *mid, *right, *o;
//上述模板注意不能用空指针
//必须从0开始,不然会RE
build(root, , N); for(int i = ; i < M; i++)
{
scanf("%d %d", &a, &b);
//树里面有0所以是a
split(root, a, left, o);
split(o, b - a + , mid, right);
mid->flip ^= ;
root = merge(merge(left, right), mid);
}
print(root);
}
return ;
}

UVA_11922 Permutation Transformer 【splay树】的更多相关文章

  1. UVA 11922 Permutation Transformer —— splay伸展树

    题意:根据m条指令改变排列1 2 3 4 … n ,每条指令(a, b)表示取出第a~b个元素,反转后添加到排列尾部 分析:用一个可分裂合并的序列来表示整个序列,截取一段可以用两次分裂一次合并实现,粘 ...

  2. UVa 11922 - Permutation Transformer 伸展树

    第一棵伸展树,各种调试模板……TVT 对于 1 n 这种查询我处理的不太好,之前序列前后没有添加冗余节点,一直Runtime Error. 后来加上冗余节点之后又出了别的状况,因为多了 0 和 n+1 ...

  3. UVA - 11922 Permutation Transformer (splay)

    题目链接 题意:你的任务是根据m条指令改变排列{!,2,3,...,n}.每条指令(a,b)表示取出第a~b个元素,翻转后添加到排列的尾部.输出最终序列. 解法:splay对区间分裂合并翻转,模板题. ...

  4. Splay树-Codevs 1296 营业额统计

    Codevs 1296 营业额统计 题目描述 Description Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司 ...

  5. ZOJ3765 Lights Splay树

    非常裸的一棵Splay树,需要询问的是区间gcd,但是区间上每个数分成了两种状态,做的时候分别存在val[2]的数组里就好.区间gcd的时候基本上不支持区间的操作了吧..不然你一个区间里加一个数gcd ...

  6. Splay树再学习

    队友最近可能在学Splay,然后让我敲下HDU1754的题,其实是很裸的一个线段树,不过用下Splay也无妨,他说他双旋超时,单旋过了,所以我就敲来看下.但是之前写的那个Splay越发的觉得不能看,所 ...

  7. 暑假学习日记:Splay树

    从昨天开始我就想学这个伸展树了,今天花了一个上午2个多小时加下午2个多小时,学习了一下伸展树(Splay树),学习的时候主要是看别人博客啦~发现下面这个博客挺不错的http://zakir.is-pr ...

  8. 1439. Battle with You-Know-Who(splay树)

    1439 路漫漫其修远兮~ 手抄一枚splay树 长长的模版.. 关于spaly树的讲解   网上很多随手贴一篇 貌似这题可以用什么bst啦 堆啦 平衡树啦 等等 这些本质都是有共同点的 查找.删除特 ...

  9. 伸展树(Splay树)的简要操作

    伸展树(splay树),是二叉排序树的一种.[两个月之前写过,今天突然想写个博客...] 伸展树和一般的二叉排序树不同的是,在每次执行完插入.查询.删除等操作后,都会自动平衡这棵树.(说是自动,也就是 ...

随机推荐

  1. Python中ndarray数组切片问题a[-n -x:-y]

    先看看如下代码: >>a=np.arange(10)>>a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>>a[-7:] array( ...

  2. UVa 11925 Generating Permutations (构造法)

    题意:给定一个序列,让你从一个升序列变成该序列,并且只有两种操作,操作1:交换前两个元素,操作2:把第一个元素移动到最后. 析:一开始的时候吧,不会,还是看的题解,首先是要逆序来做,这样可能好做一点, ...

  3. [label][转载][JavaSript]querySelectorAll 方法相比 getElementsBy 系列方法有什么区别?

     轉載出處: http://www.zhihu.com/question/24702250 querySelectorAll 相比下面这些方法有什么区别? getElementsByTagName g ...

  4. JSP和servlet之间的传值(总结的很全面)

    转自:http://blog.csdn.net/ssy_shandong/article/details/9328985 1.从一个jsp页面跳转到另一个jsp页面时的参数传递     (1)使用re ...

  5. ZooKeeper 一致性协议 ZAB 原理

    一致性协议有很多种,比如 Paxos,Raft,2PC,3PC等等,今天我们讲一种协议,ZAB 协议,该协议应该是所有一致性协议中生产环境中应用最多的了.为什么呢?因为他是为 Zookeeper 设计 ...

  6. 原创:MVC 5 实例教程(MvcMovieStore 新概念版:mvc5.0,EF6.01) - 2、数据框架 和 功能预览

    说明:MvcMovieStore项目已经发布上线,想了解最新版本功能请登录 MVC 影视(MvcMovie.cn) 进行查阅.如需转载,请注明出处:http://www.cnblogs.com/Dod ...

  7. 新手上路,django学习笔记(1) 环境部署

    很多年没写代码了,以前学的C#,用ASP.NET,但是最近几年没落了,JAVA在崛起,最近感觉Python比较火,总是在各种技术场合听到Python,或者身边的朋友在讨论Python,所以突然想学习一 ...

  8. 在相应目录下新建或读取xml文件

    string path = AppDomain.CurrentDomain.BaseDirectory+"UserContent1.xml"; //判断相应路径下文件是否存在 不存 ...

  9. C# 依赖注入 & MEF

    之前面试有问道依赖注入,因为一直是做客户端的发开发,没有接触这个,后边工作接触到了MEF,顺便熟悉一下依赖注入 详细的概念解释就不讲了,网上一大把,个人觉着依赖注入本质是为了解耦,方便扩展 依赖注入的 ...

  10. DOORS的引用类型

    DOORS的引用类型包括:Project: 项目引用Folder: 文件夹引用Item: 项目或文件夹之内的项(项目.文件夹.模块)Module: 打开模块的引用Object: 对象的引用 ...