P3391 【模板】文艺平衡树

P3391 【模板】文艺平衡树

题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列。

其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 1,翻转区间是 [2,4] 的话,结果是 5 2 3 4 1。

n,m105

思路

注意此题平衡树维护的是编号,并不是数字本身。

平衡树Splay可以实现区间翻转功能,因为平衡树的中序遍历就是原数组,所以对一颗子树的所有左右儿子对调,就实现了对这一区间区间翻转。

所以我只需要让[l,r]在一颗子树里就行,方法是先将l-1这个节点Splay到根,再把r+1这个节点Splay到l-1的右儿子位置。此时r+1的左儿子就是所求子树。

然后就是懒标记,,,打上就行

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<iomanip>
#define N 100010
#define INF 99999999
#define Ls (tr[id].s[0])
#define Rs (tr[id].s[1])
using namespace std;
int n,m,tot,root;
struct qwe{
int s[2],fa;
int val,siz;
int tag;
}tr[N];
long long read(){
long long x=0,h=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+(long long)(ch-'0');ch=getchar();}
return x*h;
}
void pushdown(int id){
if(tr[id].tag){
tr[Ls].tag^=1;
tr[Rs].tag^=1;
// 旋转的核心
swap(Ls,Rs);
tr[id].tag=0;
}
return ;
}
void print(int id){
if(id==0)return ;
pushdown(id);
print(Ls);
// printf("id:%d val:%d ls:%d rs:%d\n",id,tr[id].val,tr[id].s[0],tr[id].s[1]);
if(tr[id].val!=INF&&tr[id].val!=-INF)printf("%d ",tr[id].val);
print(Rs);
return ;
}
void pushup(int id){
// 这里记得+1,子树的根也得算进去
tr[id].siz=tr[Ls].siz+tr[Rs].siz+1;
return ;
}
int typeson(int x){
return x==tr[tr[x].fa].s[1];
}
void link(int f,int x,int tp){
tr[f].s[tp]=x;
tr[x].fa=f;
return ;
}
void rotate(int x){
int y=tr[x].fa,tp=typeson(x);
link(y,tr[x].s[tp^1],tp);
link(tr[y].fa,x,typeson(y));
link(x,y,tp^1);
pushup(y); pushup(x);
return ;
}
void splay(int x,int gl){
for(;tr[x].fa!=gl;){
int f1=tr[x].fa,f2=tr[f1].fa;
if(f2!=gl&&typeson(f1)==typeson(x))rotate(f1);
rotate(x);
}
if(gl==0)root=x;
return ;
}
int new_p(int x,int f){
++tot;
tr[tot].val=x; tr[tot].siz=1;
tr[tot].fa=f;
return tot;
}
void insert(int id,int x){
if(root==0){
root=new_p(x,0);
return ;
}
int chd=(x>tr[id].val);
if(!tr[id].s[chd]){
tr[id].s[chd]=new_p(x,id);
splay(tot,0);
}
else insert(tr[id].s[chd],x);
pushup(id);
return ;
}
int find(int id,int w){
pushdown(id);
if(w==tr[Ls].siz+1)return id;
else {
int k=(w>tr[Ls].siz+1);
if(!k)return find(Ls,w);
else return find(Rs,w-1-tr[Ls].siz);
}
}
void reverse(int l,int r){
l=find(root,l-1); r=find(root,r+1);
splay(l,0);
splay(r,l);
tr[tr[r].s[0]].tag^=1;
return ;
}
int main(){
n=read(); m=read();
// 创建虚拟节点,防止把0号节点旋到根上
insert(root,-INF); insert(root,INF);
// 这里也可以使用build建树,建树速度更快
for(int i=1;i<=n;i++)insert(root,i);
for(int i=1;i<=m;i++){
// 因为加入了虚拟节点,所以下标右移
int l=read()+1,r=read()+1;
reverse(l,r);
}
print(root);
return 0;
}
posted @   Charisk_FOD  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示