题意:

  给一个序列,是从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树)的更多相关文章

  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. UVA 11922 Permutation Transformer(Splay Tree)

    题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18902 [思路] 伸展树+打标记. 用伸展树维护这个序列,使得能 ...

  5. UVA 11922 Permutation Transformer(平衡二叉树)

    Description Write a program to transform the permutation 1, 2, 3,..., n according to m instructions. ...

  6. uva 11922 Permutation Transforme/splay tree

    原题链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18902 伸展树的区间翻转剪切... 如下: #include< ...

  7. uva 11922 - Permutation Transformer

    splay的题: 学习白书上和网上的代码敲的: #include <cstdio> #include <cstring> #include <cstdlib> #i ...

  8. uva 12003 Array Transformer (线段树套平衡树)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

  9. UVA 11525 Permutation ——(线段树,脑筋急转弯)

    只要注意到对于譬如:S1*(k-1)! 因为后面k-1个数字的全排列个数刚好是(k-1)!,那么第一个数字就是没有取过的数字的第(S1+1)个即可.取走这个数字以后这个数字就不能再用了,依次类推即可得 ...

随机推荐

  1. Opencv+Zbar二维码识别(标准条形码/二维码识别)

    使用Opencv+Zbar组合可以很容易的识别图片中的二维码,特别是标准的二维码,这里标准指的是二维码成像清晰,图片中二维码的空间占比在40%~100%之间,这样标准的图片,Zbar识别起来很容易,不 ...

  2. Top的VIRT是什么

    Top命令监控某个进程的资源占有情况  下面是各种内存: VIRT:virtual memory usage 1.进程“需要的”虚拟内存大小,包括进程使用的库.代码.数据等     2.假如进程申请1 ...

  3. jQuery 引用地址(包括jquery和google提供的地址), 节省你不必要的流量

    转载自:http://www.cnblogs.com/henw/archive/2011/09/30/2196255.html 你可以使用这句代码读取jQuery的最新版本的代码文件. jquery官 ...

  4. bzoj4555

    ntt+cdq分治 原来zwh出的cf是斯特林 第二类斯特林数的定义是S(i,j)表示将i个物品分到j个无序集合的方案数,那么这道题中S(i,j)*j!*2^j是指将i个物品分到j个有序集合中并且每个 ...

  5. pythonchallenge 2

     pythonchallenge是一个很有意思的学习python的网站,通过用程序解开一个谜,可以进入到下一个level,总共有几十个level,网址是http://www.pythonchallen ...

  6. Python网络爬虫之BeautifulSoup模块

    一.介绍: Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮 ...

  7. J20170414-ms

    ストレージ   仓库  

  8. Apache Thrift 在Windows下的安装与开发

    Windows下安装Thrift框架的教程很多.本文的不同之处在于,不借助Cygwin或者MinGW,只用VS2010,和Thrift官网下载的源文件,安装Thrift并使用. 先从官网 下载这两个文 ...

  9. ASI框架的使用

    iOS开发网络篇—简单介绍ASI框架的使用 说明:本文主要介绍网络编程中常用框架ASI的简单使用. 一.ASI简单介绍 ASI:全称是ASIHTTPRequest,外号“HTTP终结者”,功能十分强大 ...

  10. 安装kibana

    下载kibana5.1.1或者5.1.2版本的deb包,然后用dpkg命令安装 安装后启动位置在 /usr/share/kibana/bin中,在该目录下运行 ./kibana 即可启动 启动前应该先 ...