Uva 11922 Splay
Splay(伸展树)实现可分裂与合并的序列
对于BST,除了Treap树之外,还有一种Splay的伸展树,他能快速的分裂与合并。
重要的操作是伸展操作,将一个指定的结点 x 旋转到根的过程。
分三种情况,一次单旋,两次同向单旋,两次反向旋转。可以手动模拟一下这个过程。
到这里,问题常常是将序列的第 k 个元素旋转到根。
首先,要知道的是伸展树里面v存的是什么,是节点的编号(下标)。这样才能像 Treap实现名次树那样,很方便的找到左边第 k 个元素。
//将序列左数第k个元素选择到根
void splay(Node* &o,int k) {
o->pushdown();
int d = o->cmp(k);
if(d==1) k-=o->ch[0]->s + 1;
if(d!=-1) {
Node* p = o->ch[d];
p->pushdown();
int d2 = p->cmp(k);
int k2 = (d2==0 ? k : k - p->ch[0]->s - 1);
if(d2!=-1) {
splay(p->ch[d2],k2);
if(d==d2) rotate(o,d^1);
else rotate(o->ch[d],d);
}
rotate(o,d^1);
}
}
分裂与合并:
分裂:从序列从左第 k 个元素分裂,就是将序列的 o 的第 K 小元素伸展到根,断开树根与右子节点。
合并:将left部分最大的元素旋转到根,将right作为 left的右子树。(保证right>left所有元素)。
// 合并操作。假定left所有元素小于 right
Node* merge(Node* left,Node* right) {
splay(left,left->s);
left->ch[1] = right;
left->maintain();
return left;
}
//把 o 前 k 个小结点放到left里面,其他放到ritht里面,如果不够right = null
void split(Node* o,int k,Node* &left,Node* &right) {
splay(o,k);
left = o;
right = o->ch[1];
o->ch[1] = null;
left->maintain();
}
有时,对于序列有反转操作,这时,利用 线段树的 lazy标记,标记某一段是否反转。
对于,数据结构的定义:用一个Node数组,和一个Node 的 root指针,指向这个数组的元素。
#include <bits/stdc++.h> using namespace std; struct Node {
Node *ch[];
int s;
int flip;
int v;
int cmp(int k) const {
int d = k - ch[]->s;
if(d==) return -; //序列第 k 个找到
return d <= ? : ;
} void maintain() {
s = ch[]->s + ch[]->s + ;
} void pushdown() {
if(flip) {
flip = ;
swap(ch[],ch[]);
ch[]->flip = !ch[]->flip;
ch[]->flip = !ch[]->flip;
}
}
}; Node *null = new Node(); // d = 0 左旋
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;
} //将序列左数第k个元素选择到根
void splay(Node* &o,int k) {
o->pushdown();
int d = o->cmp(k);
if(d==) k-=o->ch[]->s + ;
if(d!=-) {
Node* p = o->ch[d]; p->pushdown();
int d2 = p->cmp(k);
int k2 = (d2== ? k : k - p->ch[]->s - );
if(d2!=-) {
splay(p->ch[d2],k2);
if(d==d2) rotate(o,d^);
else rotate(o->ch[d],d);
}
rotate(o,d^);
}
} // 合并操作。假定left所有元素小于 right
Node* merge(Node* left,Node* right) {
splay(left,left->s);
left->ch[] = right;
left->maintain();
return left;
} //把 o 前 k 个小结点放到left里面,其他放到ritht里面,如果不够right = null
void split(Node* o,int k,Node* &left,Node* &right) {
splay(o,k);
left = o;
right = o->ch[];
o->ch[] = null;
left->maintain();
} const int maxn = 1e5+;
struct SplaySequence {
int n;
Node seq[maxn];
Node *root; Node* build(int sz) {
if(!sz) return null;
Node* L = build(sz/);
Node* o = &seq[++n];
o->v = n;
o->ch[] = L;
o->ch[] = build(sz-sz/-);
o->flip = o ->s = ;
o->maintain();
return o;
} void init(int sz) {
n = ;
null->s = ;
root = build(sz);
for(int i = ; i < sz; i++)
printf("%d ",seq[i].v);
puts("");
} }; vector<int> ans;
void print(Node* o) {
if(o!=null) {
o->pushdown();
print(o->ch[]);
ans.push_back(o->v);
print(o->ch[]);
}
} void debug(Node* o) {
if(o!=null) {
o->pushdown();
debug(o->ch[]);
printf("%d \n",o->v -);
debug(o->ch[]);
}
} SplaySequence ss; int main()
{
int n,m;
scanf("%d%d",&n,&m);
ss.init(n+); debug(ss.root); for(int i = ; i < m; i++) {
int a,b;
scanf("%d%d",&a,&b);
Node* left,*mid,*right,*o;
split(ss.root,a,left,o);
split(o,b-a+,mid,right);
mid->flip ^=;
ss.root = merge(merge(left,right),mid);
} print(ss.root);
for(int i = ; i < (int)ans.size(); i++)
printf("%d\n",ans[i]-); return ;
}
Uva 11922 Splay的更多相关文章
- UVA 11922 Splay tree
UVA 11922 题意: 有n个数1~n 操作a,b表示取出第a~b个数,翻转后添加到数列的尾部 输入n,m 输入m条指令a,b 输出最终的序列 代码: #include<iostream&g ...
- UVa 11922 & splay的合并与分裂
题意: 1个1—n的排列,实现一下操作:将a—b翻转并移动至序列的最后. SOL: splay维护区间的裸题——不过平衡树的题目貌似都是裸的吧...就是看操作的复杂程度罢... 如何取区间呢,我们在s ...
- uva 11922 Permutation Transforme/splay tree
原题链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18902 伸展树的区间翻转剪切... 如下: #include< ...
- UVA 11922 Permutation Transformer(Splay Tree)
题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18902 [思路] 伸展树+打标记. 用伸展树维护这个序列,使得能 ...
- UVA - 11922 Permutation Transformer (splay)
题目链接 题意:你的任务是根据m条指令改变排列{!,2,3,...,n}.每条指令(a,b)表示取出第a~b个元素,翻转后添加到排列的尾部.输出最终序列. 解法:splay对区间分裂合并翻转,模板题. ...
- UVA 11922 Permutation Transformer (Splay树)
题意: 给一个序列,是从1~n共n个的自然数,接下来又m个区间,对于每个区间[a,b],从第a个到第b个从序列中分离出来,翻转后接到尾部.输出最后的序列. 思路: 这次添加了Split和Merge两个 ...
- UVA 11922 Permutation Transformer —— splay伸展树
题意:根据m条指令改变排列1 2 3 4 … n ,每条指令(a, b)表示取出第a~b个元素,反转后添加到排列尾部 分析:用一个可分裂合并的序列来表示整个序列,截取一段可以用两次分裂一次合并实现,粘 ...
- UVA 11922 伸展树Splay 第一题
上次ZOJ月赛碰到一个题目要求对序列中的某个区间求gcd,并且还要随时对某位数字进行修改 插入 删除,当时马上联想到线段树,但是线段树不支持增删,明显还是不可以的,然后就敲了个链表想暴力一下,结果TL ...
- UVa 11922 - Permutation Transformer 伸展树
第一棵伸展树,各种调试模板……TVT 对于 1 n 这种查询我处理的不太好,之前序列前后没有添加冗余节点,一直Runtime Error. 后来加上冗余节点之后又出了别的状况,因为多了 0 和 n+1 ...
随机推荐
- 修改Android解锁界面
解锁界面效果类似如下 其实这也是我后面做出的效果,样机因为没有ROOT不好调试截图,功能是将解锁的图标添加了最近运行的运用的图标,这样的话更方便用户去使用 1.分析 1.1.Android锁屏功能分析 ...
- Tomcat 启动很慢?
Tomcat 8启动很慢,在启动中, 发现加载如下类时很慢: org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom 原因 ...
- 如何看linux是32位还是64位--转
地址:http://hi.baidu.com/hehongrong/item/20c296bcf8d834432aebe3b2 如何看linux是32位还是64位 如何看linux是32位还是64位 ...
- python 模板注入
今天学习了python的模板注入,这里自己搭建环境测试以下,参考文章:http://www.freebuf.com/articles/web/136118.html web 程序包括两个文件: fla ...
- 从函数作用域和块级作用域看javascript的作用域链
在ES6之前,javascript只有全局作用域和函数作用域.所谓作用域就是一个变量定义并能够被访问到的范围.也就是说如果一个变量定义在全局(window)上,那么在任何地方都能访问到这个变量,如果这 ...
- json数据的存储与读取
1. json数据格式: data = [ {"key1":"xxx","item":"ddd"}, {"k ...
- 数据库中char、varchar、varchar2、nvarchar之间的关系
符串“abc",对于CHAR (20),表示你存储的字符将占20个字节(包括17个空字符),而同样的VARCHAR2 (20)则只占用3个字节的长度,20只是最大值,当你存储的字符小于20时 ...
- js图片上传并预览
<form id="addpic" class="easyui-form" method="post" enctype="m ...
- html页面的加载顺序
页面加载顺序: 解析HTML结构加载外部脚本和样式表文件解析并执行脚本代码构造HTML DOM模型加载图片等外部文件页面加载完毕 window.onload = function () { } / ...
- 支持触屏的zepto轮播图插件
占个座,有时间再写,呵呵 关于zepto.js,官方标准版是不支持touch的.可以去github下载压缩包,里面有所有支持的模块.我用的zepto.js,是经过打包的,包括polyfill zept ...