【模板】Splay(洛谷P3391)
Background
这是一道经典的\(\text Splay\)模板题——文艺平衡树。
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是\(5 4 3 2 1\),翻转区间是\([2,4]\)的话,结果是\(5 2 3 4 1\)
Input
第一行为\(n,m\) \(n\)表示初始序列有\(n\)个数,这个序列依次是 \((1,2, \cdots n-1,n)\) \(m\)表示翻转操作次数
接下来\(m\)行每行两个数 \([l,r]\) 数据保证 \(1 \leq l \leq r \leq n\)
Output
输出一行\(n\)个数字,表示原始序列经过\(m\)次变换后的结果
Code
#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson(x) son[x][0]
#define rson(x) son[x][1]
using namespace std;
int n,m,root,siz[200010],fa[200010],son[200010][2],tag[200010];
void updata(int u)
{
siz[u]=siz[lson(u)]+siz[rson(u)]+1;
}
void down(int u)
{
if (tag[u])
{
swap(lson(u),rson(u));
tag[u]^=1;tag[lson(u)]^=1;tag[rson(u)]^=1;
}
}
void build(int l,int r,int f)
{
if (l>r) return;
if (l==r)
{
fa[l]=f,siz[l]=1;
son[f][l>f]=l;
return;
}
int mid=(l+r)>>1;
build(l,mid-1,mid),build(mid+1,r,mid);
son[f][mid>f]=mid;fa[mid]=f;
updata(mid);
}
int find(int rt,int k)
{
down(rt);
if (siz[lson(rt)]+1==k) return rt;
if (siz[lson(rt)]>=k) return find(lson(rt),k);
else return find(rson(rt),k-siz[lson(rt)]-1);
}
void rotate(int x,int &rt)
{
int y=fa[x],z=fa[y],t=(rson(y)==x);
if (y==rt) rt=x; else son[z][rson(z)==y]=x;
fa[x]=z,fa[y]=x,fa[son[x][t^1]]=y;
son[y][t]=son[x][t^1];son[x][t^1]=y;
updata(y);updata(x);
}
void splay(int x,int &rt)
{
while (x!=rt)
{
int y=fa[x],z=fa[y];
if (y!=rt)
if (lson(z)==y ^ lson(y)==x) rotate(x,root);
else rotate(y,root);
rotate(x,root);
}
}
void rever(int l,int r)
{
l=find(root,l);r=find(root,r+2);
splay(l,root),splay(r,rson(root));
tag[lson(rson(root))]^=1;
}
int main()
{
scanf("%d%d",&n,&m);
root=(n+3)>>1;
build(1,n+2,0);
while (m--)
{
int l,r;
scanf("%d%d",&l,&r);
rever(l,r);
}
for (int i=2;i<=n+1;i++)
printf("%d ",find(root,i)-1);
return 0;
}