题目背景
这是一道经典的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
代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define MAXN 100010 using namespace std; int n,m,tot; int root,siz[MAXN],fa[MAXN],flag[MAXN],key[MAXN],ch[MAXN][2],cnt[MAXN],ans[MAXN]; void updeat(int rt){ int l=ch[rt][0],r=ch[rt][1]; siz[rt]=siz[l]+siz[r]+1; } void pushdown(int now){ if(flag[now]){ flag[ch[now][0]]^=1; flag[ch[now][1]]^=1; swap(ch[now][0],ch[now][1]); flag[now]=0; } } int getson(int x){ return ch[fa[x]][1]==x; } void rotate(int x){ int y=fa[x],z=fa[y],b=getson(x),c=getson(y),a=ch[x][!b]; if(z) ch[z][c]=x; else root=x; fa[x]=z; if(a) fa[a]=y; ch[y][b]=a; ch[x][!b]=y;fa[y]=x; updeat(y);updeat(x); } void splay(int x,int i){ while(fa[x]!=i){ int y=fa[x],z=fa[y]; if(z==i){ rotate(x); }else{ if(getson(x)==getson(y)){ rotate(y); rotate(x); }else{ rotate(x); rotate(x); } } } } int findx(int x){ int now=root; while(1){ pushdown(now); if(ch[now][0]&&x<=siz[ch[now][0]]) now=ch[now][0]; else{ int tmp=(ch[now][0]?siz[ch[now][0]]:0)+1; if(x<=tmp) return now; x-=tmp; now=ch[now][1]; } } } int build(int l,int r,int f){ int now=(l+r)/2; fa[now]=f; key[now]=ans[now]; if(l<now) ch[now][0]=build(l,now-1,now); if(r>now) ch[now][1]=build(now+1,r,now); updeat(now); return now; } void print(int now){ pushdown(now); if(ch[now][0]) print(ch[now][0]); ans[++tot]=key[now]; if(ch[now][1]) print(ch[now][1]); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n+2;i++) ans[i]=i-1; root=build(1,n+2,0); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); y=y+2; int xx=findx(x),yy=findx(y); splay(xx,0);splay(yy,xx); flag[ch[ch[root][1]][0]]^=1; } print(root); for(int i=1;i<=n;i++) printf("%d ",ans[i+1]); }