Splay 区间反转
2024-08-30 17:58:11
同样的,我们以一道题来引入。
这次的任务比较少,只要求进行区间反转。区间反转?
这个好像用啥都是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 ;
}
最新文章
- COGS130. [USACO Mar08] 游荡的奶牛[DP]
- C# 利用ICSharpCode.SharpZipLib实现在线加密压缩和解密解压缩
- Object对象类
- jquery中的cookie操作
- inux环境PHP7.0安装
- [置顶] 【SQL】查询重复人名的次数并列出
- Git 上传本地命令
- 试用cmd markdown
- malloc实现原理
- leetcode[67] Plus One
- Golang中使用lua进行扩展
- Appuim的安装步骤
- ReentrantLock 实现原理
- PHP安装过程中问题详解
- ubuntu16.04 Docker默认存储路径修改
- WCF 寄宿Windows以及控制台启动
- 【ARTS】01_10_左耳听风-20190114~20190120
- vue-element-table-js去重合并单元格解析【实战需求】
- Xshell基础入门
- SQLite的升级(转)
热门文章
- POJ-1088滑雪,典型的动态规划题,与NYOJ-10skiing一样,但NYOJ上时限是3s,用搜索可以过,但在POJ上就超时了~~
- excludepathpatterns 无效
- SOJ 4467 easyproblem 2【欧拉函数 最大公因数和】
- 2017年icpc西安网络赛 Maximum Flow (找规律+数位dp)
- 【深度探索c++对象模型】Function语义学之成员函数调用方式
- 白话空间统计之四:P值和Z值(上):零如果
- leetCode 67.Add Binary (二进制加法) 解题思路和方法
- OUTPUT 子句
- 全栈JavaScript之路(十六)HTML5 HTMLDocument 类型的变化
- IOS报错:Unexpected ‘@’ in program