Splay 区间反转
同样的,我们以一道题来引入。
这次的任务比较少,只要求进行区间反转。区间反转?
这个好像用啥都是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 区间反转的更多相关文章
- 算法模板——splay区间反转 2
实现功能:同splay区间反转 1(基于BZOJ3223 文艺平衡树) 这次改用了一个全新的模板(HansBug:琢磨了我大半天啊有木有),大大简化了程序,同时对于splay的功能也有所完善 这里面没 ...
- 算法模板——splay区间反转 1
实现的功能:将序列区间反转,并维护 详见BZOJ3223 var i,j,k,l,m,n,head,a1,a2:longint; s1:ansistring; a,b,c,d,fat,lef,rig: ...
- hdu 1890 Robotic Sort(splay 区间反转+删点)
题目链接:hdu 1890 Robotic Sort 题意: 给你n个数,每次找到第i小的数的位置,然后输出这个位置,然后将这个位置前面的数翻转一下,然后删除这个数,这样执行n次. 题解: 典型的sp ...
- HDU 1890 - Robotic Sort - [splay][区间反转+删除根节点]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890 Time Limit: 6000/2000 MS (Java/Others) Memory Li ...
- [bzoj3223]文艺平衡树(splay区间反转模板)
解题关键:splay模板题. #include<cstdio> #include<cstring> #include<algorithm> #include< ...
- HDU3487 Play with Chain splay 区间反转
HDU3487 splay最核心的功能是将平衡树中的节点旋转到他的某个祖先的位置,并且维持平衡树的性质不变. 两个操作(数组实现) cut l,r, c把[l,r]剪下来放到剩下序列中第c个后面的位置 ...
- 2018牛客网暑期ACM多校训练营(第三场) H - Shuffle Cards - [splay伸展树][区间移动][区间反转]
题目链接:https://www.nowcoder.com/acm/contest/141/C 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K ...
- hdu1890 伸展树(区间反转)
对于大神来说这题是水题.我搞这题花了快2天. 伸展树的优点有什么,就是树不管你怎么旋转序列是不会改变得,并且你要使区间反转,只要把第k大的点转到根结点,那么它的左子树就是要交换的区间[l,r),然后交 ...
- P2596 [ZJOI2006]书架 && Splay 区间操作(三)
P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...
随机推荐
- POJ1703-Find them, Catch them 并查集构造
Find them, Catch them 好久没有做并查集的题,竟然快把并查集忘完了. 题意:大致是有两个监狱,n个 ...
- bzoj 2818 GCD 数论 欧拉函数
bzoj[2818]Gcd Description 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对. Input 一个整数N Output 如题 Samp ...
- 在eclipse中画类图
学习设计模式的时候,希望能够画出类图,理清关系.但是StarUML还有重新去写类名.属性.方法等,不是很方便.网上给出了安装插件的方法额,就可以直接在eclipse中拖拽类,很方便.但是网上给出的插件 ...
- ESI 动态缓存技术[转载]
任何一个Web网站的内容都是在不断更新和变化,但这并不意味这这个网站的内容就是动态内容,事实上,动态的内容是指用户每次点击 相同的链接时取的的内容是由Web服务器应用程序生成的,如常见得ASP,JSP ...
- GOF 23种设计模式目录
经典的gof 23种设计模式,目录大纲查看. 1. Singleton(单例模式) 保证一个类只有一个实例,并提供访问它的全局访问点. 2. Abstract Factory(抽象工厂模式) 提供一个 ...
- HDU 1244 【DP】
题意: 中文. 思路: 先初步处理,用give-take求出每个城市剩的钱. 求解问题转化成使得和不小于0的最长连续字串. 枚举起点,然后当该起点加的和为负时开始枚举下一起点.(这个状态的转移) 2W ...
- CF723E(欧拉回路)
题意: 给出一个有向图,要求给每条边重定向,使得定向后出度等于入度的点最多,输出答案和任意一种方案. 分析: 将图看作无向图,对每条边重定向 首先我们肯定分成多个连通分量来考虑,每一个连通分量都是一个 ...
- 收集的一些Redis操作技巧教程
redis(1).redis入门 redis(2).redis数据类型 redis(3).基于jedis.spring-data-redis 连接操作redis redis(4).基于redis 构建 ...
- json转xml报[java.lang.NoClassDefFoundError: nu/xom/Serializer]
原文:http://blog.csdn.net/figo645/article/details/48413571 开始学习JSON了,那么很自然的,我开始要熟悉一些基本的JSON语法 {}代表对象,[ ...
- SeaGlass:手工搭建伪基站监控系统
“伪基站”即假基站,设备一般由主机和笔记本电脑或手机组成,通过短信群发器.短信发信机等相关设备能够搜取以其为中心.一定半径范围内的手机卡信息,利用2G移动通信的缺陷,通过伪装成运营商的基站,冒用他人手 ...