Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
Input
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数
接下来m行每行两个数[L,R] 数据保证 1<=L<=R<=n
Output
输出一行n个数字,表示原始序列经过m次变换后的结果
Sample Input
5 3
1 3
1 3
1 4
Sample Output
4 3 2 1 5
Hint
1≤n,m≤100000
嘛,又是一道题调一上午系列~
简单说一下区间操作,假设操作区间[L,r]。
首先明确无论怎么旋转,BST的中序遍历是不会改变的,那么我们通过伸展操作一定能得到如下图的结构:
我们发现,将L-1伸展到根,R+1伸展到根的右儿子时,上图的红色三角形就是[L,r]区间A.A,然后我们只需要像线段树一样乱搞就可以了。
//翻转之后位置会改变,但是我们可以通过size值求出它的位置
#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,R) for(register int i=(L);i<=(R);++i)
#define Red(j,R,L) for(register int j=(R);j>=(L);--j)
const int N = 1e5+10;
int n,m,a[N];
struct Splay{
bool rev[N];//翻转标记
int k[N],siz[N];
int rt,cnt,p[N],ch[N][2];
#define Ls(v) ch[v][0]
#define rs(v) ch[v][1]
#define sum(v) siz[v]=siz[Ls(v)]+siz[rs(v)]+1
inline void pushdown(int x){
if(rev[x]){
rev[Ls(x)]^=1,rev[rs(x)]^=1;
swap(Ls(x),rs(x));
rev[x]=0;
}
}
inline void rot(int x){
int f=p[x],gf=p[f],type=rs(f)==x,son=ch[x][!type];
ch[p[son]=f][type]=son,sum(f);
ch[p[f]=x][!type]=f,sum(x);
ch[p[x]=gf][rs(gf)==f]=x;
}
// int top,stk[N];
inline void splay(int x,int goal){//旋转在目标的下面
// stk[++top]=x;
// if(p[x])for(int i=x;p[i];i=p[i])stk[++top]=p[i];
// while(top)pushdown(stk[top--]);
// 提供两种写法,上面是真正的自顶向下, 不过下面因为有三个pushdown,彼此间的“无用标记”会抵消= =
// 上面的要满慢上一些
while(p[x]^goal){
if(p[p[x]])pushdown(p[p[x]]);//什么叫自顶向下
if(p[x])pushdown(p[x]);//这就叫自顶向下?
if(x)pushdown(x);//对于不清楚的地方,哈起下传标记就可以了
if((p[p[x]]^goal)&&((rs(p[p[x]])==p[x])==(rs(p[x])==x)))rot(p[x]);
rot(x);
}
if(!goal)rt=x;
}
inline int build(int L,int r){
if(L>r)return 0;
int x=++cnt,Mid=L+r>>1;
k[x]=a[Mid];
siz[x]=1;
Ls(x)=build(L,Mid-1);//我们是按照点建值,注意Mid-1
rs(x)=build(Mid+1,r);
if(Ls(x))p[Ls(x)]=x;
if(rs(x))p[rs(x)]=x;
sum(x);
return x;
}
inline int FindPos(int kth){
int x=rt;
while(1){
pushdown(x);
if(siz[Ls(x)]+1==kth)break;
if(siz[Ls(x)]+1<kth)kth-=siz[Ls(x)]+1,x=rs(x);
else x=Ls(x);
}
return x;
}
inline void reverse(int L,int r){
int Lp=FindPos(L),rp=FindPos(r);
splay(Lp,0),splay(rp,rt);
rev[Ls(rp)]^=1;
}
}sp;
inline void init(){
scanf("%d%d",&n,&m);
a[1]=-0x3f3f3f3f;//有可能操作的是[1,k]or[k,n]区间,因此要加哨兵
Inc(i,1,n)a[i+1]=i;
a[n+2]=0x3f3f3f3f;
sp.rt=sp.build(1,n+2);
}
inline void solv(){
while(m--){
int L,r;scanf("%d%d",&L,&r);
sp.reverse((L+1)-1,(r+1)+1);
}
Inc(i,2,n+1)cout<<sp.k[sp.FindPos(i)]<<" ";
}
int main(){
init();
solv();
return 0;
}