P3391 【模板】文艺平衡树(Splay)
题目背景
这是一道经典的Splay模板题——文艺平衡树。
题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
输入输出格式
输入格式:
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, \cdots n-1,n)(1,2,⋯n−1,n) m表示翻转操作次数
接下来m行每行两个数 [l,r][l,r] 数据保证 1 \leq l \leq r \leq n1≤l≤r≤n
输出格式:
输出一行n个数字,表示原始序列经过m次变换后的结果
输入输出样例
输入样例#1:
5 3 1 3 1 3 1 4
输出样例#1:
4 3 2 1 5
说明
n, m \leq 100000n,m≤100000
splay的模板题。
splay在解决区间问题的时候是先把l旋转到根节点,再把r旋转到根节点的右孩子,
然后给根节点的右孩子的左孩子打上标记。
递归修改即可
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int MAXN=100001; inline void read(int &n) { char c='+';int x=0;bool flag=0; while(c<'0'||c>'9'){c=getchar();if(c=='-')flag=1;} while(c>='0'&&c<='9'){x=x*10+(c-48);c=getchar();} n=flag==1?-x:x; } struct node { int fa,ch[2];// 左右孩子 int size;//大小 bool rev; // 是否需要旋转 }tree[MAXN]; int root=0; int n,m; inline void update(int x) {tree[x].size=tree[tree[x].ch[0]].size+tree[tree[x].ch[1]].size+1;} inline void connect(int x,int f,bool how) {tree[x].fa=f; tree[tree[x].fa].ch[how]=x;} inline void pushdown(int x) { if(tree[x].rev) swap(tree[x].ch[0],tree[x].ch[1]), tree[tree[x].ch[0]].rev^=1,tree[tree[x].ch[1]].rev^=1,tree[x].rev=0; } int build(int l,int r) { if(l>r) return 0; int mid=(l+r)>>1; connect(build(l,mid-1),mid,0); connect(build(mid+1,r),mid,1); tree[mid].rev=0; update(mid); return mid; } inline bool get(int x) { return tree[tree[x].fa].ch[1]==x; } inline int find(int x) { --x;int now=root;pushdown(now); while(x!=tree[tree[now].ch[0]].size) { if(tree[tree[now].ch[0]].size<x) x-=tree[tree[now].ch[0]].size+1, now=tree[now].ch[1]; else now=tree[now].ch[0]; pushdown(now); } return now; } inline void rotate(int x) { int f=tree[x].fa;bool d=get(x); if(f==root) root=x,tree[x].fa=0; else connect(x,tree[f].fa,get(f)); connect(tree[x].ch[!d],f,d); connect(f,x,!d); update(f); } inline void splay(int x,int r) { if(x==r) return ; for(int f;(f=tree[x].fa)!=r;) { if(tree[f].fa==r){rotate(x);break;} rotate( (get(x)==get(f))?f:x ); rotate(x); } update(x); } inline void out(int x) { if(!x) return ; pushdown(x); out(tree[x].ch[0]); if(x!=1&&x!=n+2) printf("%d ",x-1); out(tree[x].ch[1]); } int main() { freopen("sph.in","r",stdin); freopen("sph.out","w",stdout); read(n);read(m); root=build(1,n+2); int l,r,tmp; for(int i=1;i<=m;i++) { read(l);read(r); splay(find(l),0); tmp=find(r+2); splay(tmp,root); tree[tree[tmp].ch[0]].rev^=1; } out(root); return 0; }
作者:自为风月马前卒
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。