学习了splay的基本插入,删除,查询第k大树等操作以后,现在来学一下区间翻转操作。
对于翻转[l,r]这个区间,操作是这样的:把第l大的数转到根节点,把第r+2的数转到根节点的左儿子,这样处理以后会发现[l,r]的这些数都在根节点的左儿子的右子树上,然后更新一下根节点的左儿子的右儿子的tag标记。
(tag标记和线段树一样,在代码中的某些地方会下传,并且会产生某些作用,现在暂时不用管它是什么作用)
对于l,r+2是这样的:l的前一个是l-1,但由于还有一个-1e8,所以是l-1+1=l;r的后一个是r+1,但由于还有一个-1e8所以是r+1+1=r+2。
听了这个操作以后,手动模拟了第一次区间翻转后,虽然没弄懂为什么这样操作是对的,以及为什么能够想出这样高深的算法,但是这样操作确实是对的。把l-1转到根,然后再把r+2转到根的左儿子,这样的话的确[l,r]区间的数均在根的左儿子的右子树上了。
但是,为什么第二次翻转还是可以这样操作呢?我很疑惑,第一次操作过以后,不是顺序改变了嘛,原来的l,r和当前的l,r不一样了呀!
既然不一样了,为什么还能kth(l),kth(r+2)呢?
想了好久,知道了这一点:区间翻转的原理没弄懂,但是它每一次对l,r进行操作的时候,只是把splay树翻来翻去,把tag标记改来改去罢了,原序列未改变。
感觉很神奇。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,l,r,ncnt,root;
int ch[N][2],size[N],cnt[N],fa[N],val[N],tag[N];
int top,sta[N];
inline int chk(int x)
{
return ch[fa[x]][1]==x;
}
inline void pushup(int x)
{
if (!x) return;
size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];
}
inline void rotate(int x)
{
int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1];
ch[y][k]=w; fa[w]=y;
ch[z][chk(y)]=x; fa[x]=z;
ch[x][k^1]=y; fa[y]=x;
pushup(y); pushup(x);
}
inline void pushdown(int x)
{
if (!x) return;
if (tag[x])
{
tag[ch[x][0]]^=1;
tag[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
tag[x]=0;
}
}
inline void splay(int x,int goal)
{
int now=x;
while (now)
{
sta[++top]=now;
now=fa[now];
}
while (top)
{
pushdown(sta[top]);
top--;
}
while (fa[x]!=goal)
{
int y=fa[x],z=fa[y];
if (z!=goal)
{
if (chk(x)==chk(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
if (!goal) root=x;
}
inline void insert(int x)
{
ncnt++;
if (root) ch[root][1]=ncnt;
fa[ncnt]=root; val[ncnt]=x;
ch[ncnt][0]=ch[ncnt][1]=0;
cnt[ncnt]=size[ncnt]=1;
splay(ncnt,0);
}
inline int kth(int x)
{
int cur=root;
while (true)
{
pushdown(cur);
if (x<=size[ch[cur][0]]) cur=ch[cur][0];
else if (x>size[ch[cur][0]]+cnt[cur])
{
x-=size[ch[cur][0]]+cnt[cur];
cur=ch[cur][1];
}
else return cur;
}
}
inline void reverse(int l,int r)
{
l=kth(l-1),r=kth(r+1);
splay(l,0); splay(r,l);
int now=ch[ch[root][1]][0];
if (now) tag[now]^=1;
}
void dfs(int x)
{
pushdown(x);
if (ch[x][0]) dfs(ch[x][0]);
if (val[x]>=1 && val[x]<=n) printf("%d ",val[x]);
if (ch[x][1]) dfs(ch[x][1]);
}
int main(){
scanf("%d%d",&n,&m);
insert(-1e8);
for (register int i=1; i<=n; ++i) insert(i);
insert(1e8);
while (m--)
{
scanf("%d%d",&l,&r);
reverse(l+1,r+1);
}
for (register int i=1; i<=n; ++i)
{
printf("%d ",val[kth(i+1)]);
}
return 0;
}