题意:传送门
题解:
本质:翻转区间就是翻转左右的子节点。把l翻转到根节点,把r+2翻转到根节点的右节点去,那么l-r这段区间就会集中在根节点右节点的左节点里面,可以画图进行验证。
优化:但是会发现一个问题就是,如果一个区间翻转多次,岂不是很亏,不妨像线段树那样加个lazy标记,用时进行下放。这个题还有个好的优化,就是如何建树,如果一个一个插入确实可以,然后插完后会是个斜树,但是这个题是死的,所以像线段树那样建树,非常巧妙,这种方法在替罪羊树里,重新建树也是用这种方法,最后中序输出进行特判即可。
思维:这个题最关键的地方是要理解splay的操作,这不是寻常的权值搜索,而是根据位置进行操作,使用的是Kth操作,其实也是对splay的一种本质上的理解。
技巧:但是还有一个问题就是如果翻转1-n怎么办呢?那么就得在两边建立两个哨兵节点,这样就能解决所有问题了。
附上代码:
#include<bits/stdc++.h>
#define il inline
using namespace std;
il int read()
{
char ch=getchar();
int f=1,x=0;
while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int maxn=1e5+5;
const int inf=0x7fffffff;
struct node{int ch[2],ff,v,size,mark;}t[maxn];
int n,m,root,tot,val[maxn];
il void pushup(int x)
{
t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
}
il void rotate(int x)
{
int y=t[x].ff;
int z=t[y].ff;
int k=t[y].ch[1]==x;
t[z].ch[t[z].ch[1]==y]=x;
t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];
t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;
t[y].ff=x;
pushup(y);pushup(x);
}
il void Splay(int x,int goal)
{
while(t[x].ff!=goal)
{
int y=t[x].ff;int z=t[y].ff;
if(z!=goal)(t[z].ch[1]==y)^(t[y].ch[1]==x)?rotate(x):rotate(y);
rotate(x);
}
if(goal==0)root=x;
}
int build(int l,int r,int fa)
{
if(l>r)return 0;
int mid=(l+r)>>1;
int now=++tot;
t[now].size=1;
t[now].mark=0;
t[now].v=val[mid];
t[now].ch[0]=build(l,mid-1,now);
t[now].ch[1]=build(mid+1,r,now);
t[now].ff=fa;
pushup(now);
return now;
}
il void pushdown(int x)
{
if(t[x].mark)
{
t[t[x].ch[0]].mark^=1;
t[t[x].ch[1]].mark^=1;
t[x].mark=0;
swap(t[x].ch[0],t[x].ch[1]);
}
}
il int Kth(int k)
{
int u=root;
while(233)
{
pushdown(u);
if(t[t[u].ch[0]].size>=k)u=t[u].ch[0];
else if(t[t[u].ch[0]].size+1==k)return u;
else k-=t[t[u].ch[0]].size+1,u=t[u].ch[1];
}
}
il void Work(int l,int r)
{
l=Kth(l);
r=Kth(r+2);
Splay(l,0);
Splay(r,l);
t[t[t[root].ch[1]].ch[0]].mark^=1;
}
void write(int u)
{
pushdown(u);
if(t[u].ch[0])write(t[u].ch[0]);
if(t[u].v>=1&&t[u].v<=n)printf("%d ",t[u].v);
if(t[u].ch[1])write(t[u].ch[1]);
}
int main()
{
n=read();m=read();
val[1]=-inf,val[n+2]=inf;
for(int i=2;i<=n+1;i++)val[i]=i-1;
root=build(1,n+2,0);
while(m--)
{
int l=read(),r=read();
Work(l,r);
}
write(root);
printf("\n");
return 0;
}