描述 Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
输入格式 InputFormat
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n
输出格式 OutputFormat
输出一行n个数字,表示原始序列经过m次变换后的结果样例输入 SampleInput
5 3 1 3 1 3 1 4
样例输出 SampleOutput
4 3 2 1 5
数据范围和注释 Hint
n,m<=100000题解
蒟蒻我第一次打splay,代码丑,不过还算是懂了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define MAXN 100002
using namespace std;
int n,m,loc[MAXN],root,size;
int fa[MAXN],son[MAXN],tr[MAXN][2],turn[MAXN];
//fa:记录father。 son:记录节点数 tr:tree,0为左儿子,1为右儿子,turn:翻转标记
void up(int w)
{
int l=tr[w][0],r=tr[w][1];
son[w]=son[l]+son[r]+1;
}
void build(int l,int r,int f/*father*/)
{
if(l>r) return;
int p,last,mid;
if(l==r)
{p=loc[l]; last=loc[f];
fa[p]=last; son[p]=1;
if(l<f) tr[last][0]=p;
else tr[last][1]=p;
}
mid=(l+r)>>1;
p=loc[mid]; last=loc[f];
build(l,mid-1,mid); build(mid+1,r,mid);
fa[p]=last; up(mid);
if(mid<f) tr[last][0]=p;
else tr[last][1]=p;
}
void init()
{
scanf("%d%d",&n,&m);
int i;
for(i=1;i<=n+2;i++) loc[i]=++size;//为了防止数组超界。
build(1,n+2,0); root=(n+3)>>1; //(n+2+1)>>1;
}
//----------------------------------------------以上为预处理。
void down(int w)//标记下传
{
int l=tr[w][0],r=tr[w][1];
if(turn[w])
{swap(tr[w][0],tr[w][1]); //这里不能用l、r代替
turn[l]^=1; turn[r]^=1;
turn[w]=0;
}
}
int find(int w,int x)//找树中标记,与treap类似
{
down(w);
int l=tr[w][0],r=tr[w][1];
if(son[l]+1==x) return w;
else if(son[l]>=x) return find(l,x);
else return find(r,x-son[l]-1);
}
void rotate(int x,int &w)//旋转--具体步骤
{
int y=fa[x],z=fa[y],l,r;
if(tr[y][0]==x) l=0;
else l=1;
r=l^1;
if(y==w) w=x;
else
{if(tr[z][0]==y) tr[z][0]=x;
else tr[z][1]=x;
}
fa[x]=z; fa[y]=x; fa[tr[x][r]]=y;
tr[y][l]=tr[x][r]; tr[x][r]=y;
up(y); up(x);
}
void splay(int x,int &w)//旋转--大步骤
{
while(x!=w)
{int y=fa[x],z=fa[y];
if(y!=w)
{if((tr[y][0]==x)^(tr[z][0]==y)) rotate(x,w);
else rotate(y,w);
}
rotate(x,w);
}
}
void overturn(int l,int r) //翻转操作
{
int x=find(root,l),y=find(root,r+2);//为了方便,splay中所有元素标号+1,如1号元素标号为2
splay(x,root); splay(y,tr[x][1]);
int z=tr[y][0];
turn[z]^=1;
}
void work()
{
int i,l,r;
for(i=1;i<=m;i++)
{scanf("%d%d",&l,&r);
overturn(l,r);
}
for(int i=2;i<=n+1;i++)
printf("%d ",find(root,i)-1);
}
int main()
{
init(); work();
return 0;
}