UVA 11922 Permutation Transformer (Splay树)
题意:
给一个序列,是从1~n共n个的自然数,接下来又m个区间,对于每个区间[a,b],从第a个到第b个从序列中分离出来,翻转后接到尾部。输出最后的序列。
思路:
这次添加了Split和Merge两个基本操作,还有个比较困难的翻转操作。翻转操作只需要将需要翻转的序列独立成树,给根加上翻转标记之后再直接插到另外由前后两棵树组成的树上。但是在做一些操作的时候可能会遇到已经标记了翻转的子树,比如splay时,如果不顾flip标记,直接带flip标记的点伸展到根,会就会跟其他没有标记的节点混合了,而一个点如果带flip标记,其实标记的是它的两个孩子是需要翻转,此时如果来个无标记的孩子替换了某个孩子,就会造成错误。所以必须在splay之前完成翻转。
#include <bits/stdc++.h>
#define pii pair<int,int>
#define INF 0x3f7f7f7f
#define LL long long
using namespace std;
const int N=;
const int mod=; struct node
{
int key, pre, flip, ch[], son[];
}nod[N];
int n, m, a, b, node_cnt, root; int create_node(int v,int far)
{
nod[node_cnt].key=v;
nod[node_cnt].pre=far;
nod[node_cnt].flip=;
nod[node_cnt].ch[]=;
nod[node_cnt].ch[]=;
nod[node_cnt].son[]=;
nod[node_cnt].son[]=;
return node_cnt++;
} void push_down(int t)
{
if(nod[t].flip)
{
swap(nod[t].ch[], nod[t].ch[]);
swap(nod[t].son[], nod[t].son[]);
nod[t].flip=;
int L=nod[t].ch[], R=nod[t].ch[];
if(L) nod[L].flip=!nod[L].flip;
if(R) nod[R].flip=!nod[R].flip;
}
} void Rotate(int t,int d)
{
int son=nod[t].ch[d];
int far=nod[t].pre;
int gra=nod[far].pre; nod[son].pre=far;
nod[far].pre=t;
nod[t].pre=gra; nod[t].ch[d]=far;
nod[far].ch[d^]=son;
nod[gra].ch[ nod[gra].ch[]==far ]=t; nod[far].son[d^]=nod[t].son[d];
nod[t].son[d]+=nod[far].son[d]+;
} int Insert(int t,int v)
{
if(t==) return root=create_node(v, );
if( v<nod[t].key )
{
if(nod[t].ch[]) return Insert(nod[t].ch[], v);
else return nod[t].ch[]=create_node(v, t);
}
else
{
if(nod[t].ch[]) return Insert(nod[t].ch[], v);
else return nod[t].ch[]=create_node(v, t);
}
} void Splay(int t,int goal)
{
while(nod[t].pre!=goal)
{
int f=nod[t].pre, g=nod[f].pre;
if(g==goal) Rotate(t, nod[f].ch[]==t);
else
{
int d1=nod[f].ch[]==t, d2=nod[g].ch[]==f;
if(d1==d2) Rotate(f, d1),Rotate(t, d1);
else Rotate(t, d1),Rotate(t, d2);
}
}
if(!goal) root=t;
} int Find(int t,int k) //找第k个元素,必须能找到。这里不处理出错。
{
push_down(t); //找的时候顺便往下推。
if( nod[t].son[]+==k ) return t;
if( k<nod[t].son[]+ ) return Find(nod[t].ch[], k);
else return Find(nod[t].ch[], k-nod[t].son[]-);
} void Split(int t, int k, int &L, int &R) //在以t为根的树中将[1,k]分离出来,变成两棵树L和R。
{
Splay( Find(t, k), ); //查找第k个元素,并伸展到根
L=root;
R=nod[L].ch[];
nod[L].son[]=;
nod[L].ch[]=;
nod[R].pre=;
} int Merge(int L,int R)
{
int k=nod[L].son[]+nod[L].son[]+;
Splay( Find(L, k), ); //在用Splay时,必须先往下推。
L=root;
nod[L].ch[]=R;
nod[R].pre=L;
nod[L].son[]=nod[R].son[]++nod[R].son[];
return L;
} void cal(int a,int b) //从树中取出[a,b]然后旋转,插到尾部
{
int left=, mid=, right=;
if(a!= && b!=n) //三段
{
Split(root, a-, left, right);
Split(right, b-a+, mid, right );
nod[mid].flip^=;
root=Merge(Merge( left, right ) , mid );
}
else if(a==) //中后段
{
Split(root, b, mid, right );
nod[mid].flip^=;
root=Merge( right, mid );
}
else if(b==n) //前中段
{
Split(root, a-, left, mid);
nod[mid].flip^=;
root=Merge(left, mid );
}
} void print(int t) //深搜输出
{
push_down(t); //要往下推
if(nod[t].ch[]) print(nod[t].ch[]);
printf("%d\n", nod[t].key);
if(nod[t].ch[]) print(nod[t].ch[]);
} int main()
{
//freopen("input.txt", "r", stdin);
node_cnt=;root=;
cin>>n>>m;
for(int i=; i<=n; i++) Splay(Insert(root, i), ); for(int i=; i<m; i++)
{
scanf("%d%d",&a,&b);
if(a== && b==n) nod[root].flip^=; //整个区间都翻转
cal(a,b);
}
print(root);
return ;
}
AC代码
UVA 11922 Permutation Transformer (Splay树)的更多相关文章
- UVA 11922 Permutation Transformer —— splay伸展树
题意:根据m条指令改变排列1 2 3 4 … n ,每条指令(a, b)表示取出第a~b个元素,反转后添加到排列尾部 分析:用一个可分裂合并的序列来表示整个序列,截取一段可以用两次分裂一次合并实现,粘 ...
- UVa 11922 - Permutation Transformer 伸展树
第一棵伸展树,各种调试模板……TVT 对于 1 n 这种查询我处理的不太好,之前序列前后没有添加冗余节点,一直Runtime Error. 后来加上冗余节点之后又出了别的状况,因为多了 0 和 n+1 ...
- UVA - 11922 Permutation Transformer (splay)
题目链接 题意:你的任务是根据m条指令改变排列{!,2,3,...,n}.每条指令(a,b)表示取出第a~b个元素,翻转后添加到排列的尾部.输出最终序列. 解法:splay对区间分裂合并翻转,模板题. ...
- UVA 11922 Permutation Transformer(Splay Tree)
题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18902 [思路] 伸展树+打标记. 用伸展树维护这个序列,使得能 ...
- UVA 11922 Permutation Transformer(平衡二叉树)
Description Write a program to transform the permutation 1, 2, 3,..., n according to m instructions. ...
- uva 11922 Permutation Transforme/splay tree
原题链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18902 伸展树的区间翻转剪切... 如下: #include< ...
- uva 11922 - Permutation Transformer
splay的题: 学习白书上和网上的代码敲的: #include <cstdio> #include <cstring> #include <cstdlib> #i ...
- uva 12003 Array Transformer (线段树套平衡树)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...
- UVA 11525 Permutation ——(线段树,脑筋急转弯)
只要注意到对于譬如:S1*(k-1)! 因为后面k-1个数字的全排列个数刚好是(k-1)!,那么第一个数字就是没有取过的数字的第(S1+1)个即可.取走这个数字以后这个数字就不能再用了,依次类推即可得 ...
随机推荐
- skynet源码阅读<4>--定时器实现
昨天和三石公聊天,他提到timer的实现原理,我当时迟疑了一下,心想timer不是系统底层时钟中断驱动上层进程/线程,累积计时实现的么?他简述了timer的实现,什么堆排序,优先级队列等,与我想象的不 ...
- BlueSea笔记<1>--Cricket初探
最近在看Cricket这个实现了Actor模式的F#开源框架,对其工作方式作了一番探究.首先来看一段简单的例子代码: type Say = | Hello let greeter = actor { ...
- ASP.NET Core:WebAppCoreRESTful
ylbtech-ASP.NET Core:WebAppCoreRESTFul 1.返回顶部 1. 2. 3. 4. 2. Controllers返回顶部 1.HomeControlle ...
- python整数与IP地址转换 [转]
我们有时会将一个整数与IP地址进行互换,用python代码实现很简单将一个整数如2000000,变为一个IP地址的方式 >>> import socket >>> ...
- docker使用问题
在deepin linux操作系统中安装docker-engine后启动失败. Version: 1.12.3API version: 1.24Go version: go1.6.3 错误1: 使用d ...
- J2ee的SSM和SSH的小结
1.介绍SSM框架: SSM是指由Spring.SpringMVC.Mybatis三个开源框架整合的开发框架. a).Spring是一个轻量级的容器框架,核心是控制反转(IoC)和面向切面(AOP). ...
- 由mysql分区想到的分表分库的方案
在分区分库分表前一定要了解分区分库分表的动机. 对实时性要求比较高的场景,使用数据库的分区分表分库. 对实时性要求不高的场景,可以考虑使用索引库(es/solr)或者大数据hadoop平台来解决(如数 ...
- E20180403-hm
accompany vt. 陪伴,陪同; 附加,补充; 与…共存; 为…伴奏 synchronous adj. 同时存在[发生]的,同步的 asynchronous adj. 异步的; particu ...
- 51nod 1004 【快速幂】
思路: 掐住最后一位,快速幂一发就好了 #include<cstdio> #include <map> #include<iostream> #include< ...
- 第八篇 .NET高级技术之字符串暂存池(缓冲池)
字符串不可变性,字符串的‘暂存池’两个特性 字符串是引用类型,程序中会存在大量的字符串对象,如果每次都创建一个字符串对象,会比较浪费内存.性能低,因此CLR做了“暂存池”(拘留池,缓冲池,暂存池),在 ...