BZOJ3223 文艺平衡树

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=ch[f][1]==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][ch[gf][1]==f]=x;
	}
	inline void splay(int x,bool flag){
		while(p[x]){
			if(!flag&&x==rs(rt))break;
			if(p[p[x]])pushdown(p[p[x]]);//什么叫自顶向下 
			if(p[x])pushdown(p[x]);//这就叫自顶向下!!! 
			if(x)pushdown(x);//对于不清楚的地方,哈起下传标记就可以了 
			if(flag&&p[p[x]]&&((ch[p[p[x]]][1]==p[x])==(ch[p[x]][1]==x)))rot(p[x]);
			else if(!flag&&p[x]!=rs(rt)&&((ch[p[p[x]]][1]==p[x])==(ch[p[x]][1]==x)))rot(p[x]);
			rot(x);
		}
		if(flag)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);
		sum(x);
		if(Ls(x))p[Ls(x)]=x;
		if(rs(x))p[rs(x)]=x;
		return x;
	}
	inline int FindP(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=FindP(L),rp=FindP(r);
		splay(Lp,1);
		splay(rp,0);
		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,r+2);
	}
	Inc(i,2,n+1)cout<<sp.k[sp.FindP(i)]<<" ";
}
int main(){
	init();
	solv();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dancingz/article/details/81078861