文艺平衡树

Describe:

给定一个有 \(n\) 个元素且没有重复元素的序列,进行 \(m\) 次翻转操作,输出最终序列。

Solution:

翻转操作类似 LCT 中的 makeroot,稍加改造即可。

splay 有一个很好的性质,就是旋转过后也不改变中序遍历的顺序。所以若将左右子树交换且对子树内的节点做同样的操作,就是一次中序遍历的翻转。所以只要把区间单独分离出一个子树,就可以很好的实现翻转操作。

对于区间 \(\left[l,r\right]\),可以把 \(l\) 的前驱旋转到根上,再把 \(r\) 的后继旋转到右子树,这样整个区间 \(\left[l,r\right]\) 都在根的右子树的左子树。(如下图)

image

当然,你让 \(r\) 的后继当根也没问题,这样区间 \(\left[l,r\right]\) 就应对应根的左子树的右子树。最后按中序遍历输出即可。

Code:

bool _Start;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
// #define DEBUG
namespace IO
{
	#define TP template<typename T>
	#define TP_ template<typename T,typename ... T_>
	#ifdef DEBUG
	#define gc() (getchar())
	#else
	char buf[1<<20],*p1,*p2;
	#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
	#endif
	#ifdef DEBUG
	void pc(const char &c)
	{
		putchar(c);
	}
	#else
	char pbuf[1<<20],*pp=pbuf;
	void pc(const char &c)
	{
		if(pp-pbuf==1<<20)
			fwrite(pbuf,1,1<<20,stdout),pp=pbuf;
		*pp++=c;
	}
	struct IO{~IO(){fwrite(pbuf,1,pp-pbuf,stdout);}}_;
	#endif
	TP void read(T &x)
	{
		x=0;static int f;f=0;static char ch;ch=gc();
		for(;ch<'0'||ch>'9';ch=gc())ch=='-'&&(f=1);
		for(;ch>='0'&&ch<='9';ch=gc())x=(x<<1)+(x<<3)+(ch^48);
		f&&(x=-x);
	}
	TP void write(T x)
	{
		if(x<0)
			pc('-'),x=-x;
		static T sta[35],top;top=0;
		do
			sta[++top]=x%10,x/=10;
		while(x);
		while(top)
			pc(sta[top--]^48);
	}
	TP_ void read(T &x,T_&...y){read(x);read(y...);}
	TP void writeln(const T x){write(x);pc('\n');}
	TP void writesp(const T x){write(x);pc(' ');}
	TP_ void writeln(const T x,const T_ ...y){writesp(x);writeln(y...);}
	TP void debugsp(const T x){fprintf(stderr,"%d ",x);}
	TP void debug(const T x){fprintf(stderr,"%d\n",x);}
	TP_ void debug(const T x,const T_...y){debugsp(x);debug(y...);}
	TP inline T max(const T &a,const T &b){return a>b?a:b;}
	TP_ inline T max(const T &a,const T_&...b){return max(a,max(b...));} 
	TP inline T min(const T &a,const T &b){return a<b?a:b;}
	TP_ inline T min(const T &a,const T_&...b){return min(a,min(b...));}
	TP inline void swap(T &a,T &b){static T t;t=a;a=b;b=t;}
	TP inline T abs(const T &a){return a>0?a:-a;}
	#undef TP
	#undef TP_
}
using namespace IO;
using std::cerr;
using LL=long long;
constexpr int N=1e5+5,inf=1e9;
struct trnode
{
	int son[2],fa,siz,c;
	int tag;
}tr[N];int trlen,rt;
#define lc(x) tr[x].son[0]
#define rc(x) tr[x].son[1]
#define fa(x) tr[x].fa
void pushup(int x)
{
	tr[x].siz=tr[lc(x)].siz+tr[rc(x)].siz+1;
}
void add(int c,int fa)
{
	tr[++trlen]={0,0,fa,1,c,0};
	tr[fa].son[tr[fa].c<c]=trlen;
}
void pushdown(int x)
{
	if(tr[x].tag)
	{
		tr[lc(x)].tag^=1;
		tr[rc(x)].tag^=1;
		swap(lc(x),rc(x));
		tr[x].tag=0;
	}
}
void rotate(int x)
{
	int y=fa(x),z=fa(y);
	pushdown(y),pushdown(x);
	int k=(rc(y)==x);
	tr[z].son[rc(z)==y]=x;fa(x)=z;
	tr[y].son[k]=tr[x].son[k^1];fa(tr[x].son[k^1])=y;
	tr[x].son[k^1]=y;fa(y)=x;
	pushup(y),pushup(x);
}
void splay(int x,int root)
{
	while(fa(x)!=root)
	{
		int y=fa(x),z=fa(y);
		if(z!=root)
			((rc(y)==x)^(rc(z)==y))?rotate(x):rotate(y);
		rotate(x);
	}
	if(!root)
		rt=x;
}
int findkth(int k)
{
	int x=rt;
	while(1)
	{
		pushdown(x);
		if(k>tr[lc(x)].siz+1)
		{
			k-=tr[lc(x)].siz+1;
			x=rc(x);
		}
		else if(k<=tr[lc(x)].siz)
			x=lc(x);
		else
			return x;
	}
}
void turn(int l,int r)
{
	l=findkth(l);
	r=findkth(r+2);
	splay(l,0);
	splay(r,l);
	pushdown(rt);
	tr[lc(rc(rt))].tag^=1;
}
void output(int x)
{
	pushdown(x);
	if(lc(x))
		output(lc(x));
	if(tr[x].c!=inf&&tr[x].c!=-inf)
		writesp(tr[x].c);
	if(rc(x))
		output(rc(x));
}
int n,q,a[N];
int build(int fa,int l,int r)
{
	if(l>r)
		return 0;
	int mid=(l+r)>>1;
	add(a[mid],fa);
	int now=trlen;
	lc(now)=build(now,l,mid-1);
	rc(now)=build(now,mid+1,r);
	pushup(now);
	return now;
}
bool _End;
int main()
{
	//fprintf(stderr,"%.2 MBlf\n",(&_End-&_Start)/1048576.0);
	read(n,q);
	a[1]=-inf;
	for(int i=1;i<=n;i++)
		a[i+1]=i;
	a[n+2]=inf;
	rt=build(0,1,n+2);
	while(q--)
	{
		int l,r;
		read(l,r);
		turn(l,r);
	}
	output(rt);
	return 0;
}
posted @ 2024-02-15 16:36  wmtl_lofty  阅读(39)  评论(0)    收藏  举报