Describe:
给定一个有 \(n\) 个元素且没有重复元素的序列,进行 \(m\) 次翻转操作,输出最终序列。
Solution:
翻转操作类似 LCT 中的 makeroot,稍加改造即可。
splay 有一个很好的性质,就是旋转过后也不改变中序遍历的顺序。所以若将左右子树交换且对子树内的节点做同样的操作,就是一次中序遍历的翻转。所以只要把区间单独分离出一个子树,就可以很好的实现翻转操作。
对于区间 \(\left[l,r\right]\),可以把 \(l\) 的前驱旋转到根上,再把 \(r\) 的后继旋转到右子树,这样整个区间 \(\left[l,r\right]\) 都在根的右子树的左子树。(如下图)
当然,你让 \(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;
}
标签:int,siz,tr,文艺,fa,平衡,now,define
From: https://www.cnblogs.com/lofty2007/p/18016343