P3391 【模板】文艺平衡树
题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列。
其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 1,翻转区间是 [2,4] 的话,结果是 5 2 3 4 1。
思路
注意此题平衡树维护的是编号,并不是数字本身。
平衡树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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!