同样的,我们以一道题来引入。

传送门

这次的任务比较少,只要求进行区间反转。区间反转?

这个好像用啥都是O(n)的吧……(这次vector,set也救不了你了)

我们来使用splay解决这个问题。我们既然要反转一段区间,那我们肯定要把这个区间弄到一个地方。我们想一下上次所讲的删除操作,我们把要删除的数的前驱后继都找了出来并且一个旋转到根,一个到根的右儿子。我们思考一下发现,如果把这个区间第一个数的前一个数(l-1)旋转到根,把区间最后一个数的后一个数(r+1)旋转到根的右儿子,那么现在根的右儿子的左子树就是这个区间了!

然后我们就可以大力(划死)操作这棵子树,比如进行区间加减,区间翻转。翻转其实很简单,我们只要打上一个标记,在下放标记的时候,我们把当前节点的左右子树交换,把左右子树的标记全部异或1,把这个点的标记清零即可。(和线段树下放lazy标记非常像)

然后实际操作的时候,比如我们要翻转区间2~4,我们不是真的去找这俩数在哪,因为我们要反转的话其实和数的大小是无关的,和下标的大小是有关的。取而代之的,我们找到在这棵平衡树中相对应的排名为2和排名为4的两个数的编号是多少,之后我们对它们进行操作即可。

然后最后我们在输出整棵树的时候只要输出其中序遍历即可。

我们来看一下代码吧!

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = ;
const int N = ;
const int INF = ; int read()
{
int ans = ,op = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') op = -;
ch = getchar();
}
while(ch >='' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
return ans * op;
} struct node
{
int fa,ch[],son,cnt,tag,val;
}t[M<<]; int n,m,data[M<<],root,x,y,idx; bool get(int x)
{
return t[t[x].fa].ch[] == x;
} void pushup(int x)
{
t[x].son = t[t[x].ch[]].son + t[t[x].ch[]].son + ;//题中无重复的数
} void pushdown(int x)
{
if(x && t[x].tag)
{
t[t[x].ch[]].tag ^= ,t[t[x].ch[]].tag ^= ;
swap(t[x].ch[],t[x].ch[]);
t[x].tag = ;
}
} void rotate(int x)
{
int y = t[x].fa,z = t[y].fa,k = get(x);
t[z].ch[t[z].ch[] == y] = x,t[x].fa = z;
t[y].ch[k] = t[x].ch[k^],t[t[y].ch[k]].fa = y;
t[x].ch[k^] = y,t[y].fa = x;
pushup(x),pushup(y);
} void splay(int x,int goal)
{
while(t[x].fa != goal)
{
int y = t[x].fa,z = t[y].fa;
if(z != goal) (t[y].ch[] == x) ^ (t[z].ch[] == y) ? rotate(x) : rotate(y);
rotate(x);
}
if(goal == ) root = x;
} int rk(int x)//找排名
{
int u = root;
while()
{
pushdown(u);
if(t[t[u].ch[]].son >= x) u = t[u].ch[];
else
{
x -= (t[t[u].ch[]].son + );
if(!x) return u;
u = t[u].ch[];
}
}
} int build(int f,int l,int r)//直接构造一棵完美的splay
{
if(l > r) return ;
int mid = (l+r) >> ,u = ++idx;
t[u].val = data[mid],t[u].fa = f;//注意一定是mid的值!
t[u].ch[] = build(u,l,mid-);
t[u].ch[] = build(u,mid+,r);
pushup(u);
return u;
} void turn(int x,int y)
{
int a = rk(x), b = rk(y+);//因为插入了正负INF,所以相对应都向后移了一位
splay(a,),splay(b,a);//以下操作上面都说过
pushdown(root);
int g = t[t[root].ch[]].ch[];
t[g].tag ^= ;
} void write(int x)//输出中序遍历
{
pushdown(x);
if(t[x].ch[]) write(t[x].ch[]);
if(t[x].val != INF && t[x].val != -INF) printf("%d ",t[x].val);
if(t[t[x].ch[]].val) write(t[x].ch[]);
} int main()
{
n = read(),m = read();
rep(i,,n) data[i+] = i;
data[] = -INF,data[n+] = INF;//防止出错
root = build(,,n+);
rep(i,,m) x = read(),y = read(),turn(x,y);
write(root);
return ;
}

Splay 区间反转的更多相关文章

  1. 算法模板——splay区间反转 2

    实现功能:同splay区间反转 1(基于BZOJ3223 文艺平衡树) 这次改用了一个全新的模板(HansBug:琢磨了我大半天啊有木有),大大简化了程序,同时对于splay的功能也有所完善 这里面没 ...

  2. 算法模板——splay区间反转 1

    实现的功能:将序列区间反转,并维护 详见BZOJ3223 var i,j,k,l,m,n,head,a1,a2:longint; s1:ansistring; a,b,c,d,fat,lef,rig: ...

  3. hdu 1890 Robotic Sort(splay 区间反转+删点)

    题目链接:hdu 1890 Robotic Sort 题意: 给你n个数,每次找到第i小的数的位置,然后输出这个位置,然后将这个位置前面的数翻转一下,然后删除这个数,这样执行n次. 题解: 典型的sp ...

  4. HDU 1890 - Robotic Sort - [splay][区间反转+删除根节点]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890 Time Limit: 6000/2000 MS (Java/Others) Memory Li ...

  5. [bzoj3223]文艺平衡树(splay区间反转模板)

    解题关键:splay模板题. #include<cstdio> #include<cstring> #include<algorithm> #include< ...

  6. HDU3487 Play with Chain splay 区间反转

    HDU3487 splay最核心的功能是将平衡树中的节点旋转到他的某个祖先的位置,并且维持平衡树的性质不变. 两个操作(数组实现) cut l,r, c把[l,r]剪下来放到剩下序列中第c个后面的位置 ...

  7. 2018牛客网暑期ACM多校训练营(第三场) H - Shuffle Cards - [splay伸展树][区间移动][区间反转]

    题目链接:https://www.nowcoder.com/acm/contest/141/C 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K ...

  8. hdu1890 伸展树(区间反转)

    对于大神来说这题是水题.我搞这题花了快2天. 伸展树的优点有什么,就是树不管你怎么旋转序列是不会改变得,并且你要使区间反转,只要把第k大的点转到根结点,那么它的左子树就是要交换的区间[l,r),然后交 ...

  9. P2596 [ZJOI2006]书架 && Splay 区间操作(三)

    P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...

随机推荐

  1. 【贪心】codeforces A. Heidi and Library (easy)

    http://codeforces.com/contest/802/problem/A [题意] 有一个图书馆,刚开始没有书,最多可容纳k本书:有n天,每天会有人借一本书,当天归还:如果图书馆有这个本 ...

  2. 虫食算(codevs 1064)

    题目描述 Description 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045    +    8468#6 ...

  3. 【ZJOI2017 Round1练习&BZOJ4767】D1T3 两双手(排列组合,DP)

    题意: 100%的数据:|Ax|,|Ay|,|Bx|,|By| <= 500, 0 <= n,Ex,Ey <= 500 思路:听说这是一道原题 只能往右或者下走一步且有禁止点的简化版 ...

  4. 前端的指导方针---css篇

    英语是渣渣,想学英语,又不想花钱报培训班.看不懂的文章,还是翻译一下留着自己看吧. 引自   :  https://github.com/bendc/frontend-guidelines HTML ...

  5. IO与文件读写---Java的IO流架构

    http://www.blogjava.net/pengpenglin/archive/2010/03/03/314239.html#314399 http://www.blogjava.net/jo ...

  6. spring mvc get请求也可以接受DTO对象

    spring mvc get请求也可以接受DTO对象,比如:url上面你还是将参数&符号连接起来,并自动封装进一个DTO对象里. 只有@RequestBody注解spring mvc才会从ht ...

  7. .NET 之 ORM 性能评测

    .NET 之 ORM 性能评测 Why 你应该总能听到某ORM性能比Dapper高 你应该有如下疑问: 基准测试是否权威 基准测试的方式是否合理 基准测试的标准是否能够统一 统一基准测试标准/规范 如 ...

  8. rand和srand的用法(转载)

    首先我们要对rand&srand有个总体的看法:srand初始化随机种子,rand产生随机数,下面将详细说明. rand(产生随机数)表头文件: #include<stdlib.h> ...

  9. c# 把一个匿名对象赋值给一个Object类型的变量后,怎么取这个变量? c# dynamic动态类型和匿名类 详解C# 匿名对象(匿名类型)、var、动态类型 dynamic 深入浅析C#中的var和dynamic

    比如有一个匿名对象,var  result =......Select( a=>new {  id=a.id, name=a.name});然后Object  obj =  result ;我怎 ...

  10. soapUI系列之—-01 介绍soapUI简介,groovy 简介

    1.soapui简介 SoapUI是一个自由和开放源码的跨平台功能测试解决方案.通过一个易于使用的图形界面和企业级功能,SoapUI让您轻松,快速创建和执行自动化功能.回归.合规和负载测试.在一个测试 ...