题意:

  给一个序列,是从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. poj 2406 Power Strings(kmp求一个串的重复子串)

    题意:重复子串次数 思路:kmp #include<iostream> #include<stdio.h> #include<string.h> using nam ...

  2. 51Nod 1717

    链接 分析:对于任意一个数,它的约数总是成对出现的,但是对于完全平方数,它因为有两个约数不相等,所以只会出现奇数次,所以最终的结果就是减去完全平方数 #include "iostream&q ...

  3. YUIDoc的使用方法小结

    一.YUIDoc概述以及安装YUIDoc是为YUI Library用来生成HTML版API文档的一系列工具集,文档的生成完全基于JavaDoc风格的代码注释规则.该工具是基于Python语言编写,并且 ...

  4. 洛谷P1999三国游戏

    题目:https://www.luogu.org/problemnew/show/P1199 仔细想想,两方都拿不到每个武将的配对中最大的: 本来想的是如果有武将a,b,对应最大ma,mb,次大ca, ...

  5. iphone 在设置了initial-scale=1 之后,在设置滚动条之后,没有滑动效果的解决办法

    iphone在设置了initial-scale=1 之后,我们终于可以以1:1 的比例进行页面设计了. 关于viewport,还有一个很重要的概念是:iphone 的safari 浏览器完全没有滚动条 ...

  6. css 样式引入的方法 link 与import的区别

    <link> 元素所参考的样式用户可以自由的选择加以改变,而导入的样式表单就自动的与剩下的样式表融合在一起了 CSS与HTML文档结合的4中方法:1 使用<link>元素链接到 ...

  7. 国外1.5免费空间000webhost申请方法

    空间大小:1500M 支持语言:PHP 数 据 库:MYSQL 国家/地区:国外 申请地址:http://www.000webhost.com/   1500M/100GB/PHP/MYSQL/FTP ...

  8. ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 08. 输入Model和防止重复Post

    通过action的参数传入一个model 通过input的name属性和model属性对应上 通常是使用Http post去做 快速创建了这个Action 这个Action很简单我们只需要返回View ...

  9. ORACLE PL/SQL 实例精解之第二章 通用编程语言基础

    通用编程语言基础 2.1PL/SQL编程基础 1. 字符类型:支持四中类型字符:字母,数字,符号和空格,组合一个或多个字符就会创建一个词汇单元 2. 词汇单元 a.标识符必须以字符开头 b.保留字是p ...

  10. Educational Codeforces Round 21E selling souvenirs (dp)

    传送门 题意 给出n个体积为wi,价值为ci的物品,现在有一个m大的背包 问如何装使得最后背包内的物品价值最大,输出价值 分析 一般的思路是01背包,但n*v不可做 题解的思路 We can iter ...