背景:
发现
s
p
l
a
y
splay
splay学得像
s
h
i
t
shit
shit使得,重新搞过,顺带写博客。
题目传送门:
https://www.luogu.org/problemnew/show/P3391
题意:
维护一个支持区间翻转的序列。
思路:
显然我们不能直接在
s
p
l
a
y
splay
splay中操作。
容易发现对一个区间进行两次翻转的效果是不变的。不妨用
l
a
z
y
lazy
lazy来记录当前节点是否需要翻转。
因为
s
p
l
a
y
splay
splay的性质(左儿子<根<右儿子)满足了区间翻转就是交换字树内的左右儿子,那就可以让
l
a
z
y
lazy
lazy下传。
考虑到这里我们还是不知道该如何旋转区间
[
l
,
r
]
[l,r]
[l,r]。你在想想
s
p
l
a
y
splay
splay还有那些性质。我们将
l
−
1
l-1
l−1这个点旋转作为整棵树的根,那么再将
r
+
1
r+1
r+1旋转作为当前根的右儿子,那么要翻转的区间就是
r
+
1
r+1
r+1的左儿子所管理的子树,直接打上
l
a
z
y
lazy
lazy标志即可。
由于可能会出现
0
0
0这样的节点,所以整体偏移一位即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{int d,fa,c,n,son[2],lazy;} tr[100010];
int n,m,root=0,len=0;
void ups(int x)
{
int lc=tr[x].son[0],rc=tr[x].son[1];
tr[x].c=tr[lc].c+tr[rc].c+tr[x].n;
if(tr[x].lazy)
{
tr[lc].lazy^=1,tr[rc].lazy^=1;
tr[x].son[0]=rc,tr[x].son[1]=lc;
tr[x].lazy=0;
}
}
void add(int d,int fa)
{
tr[++len]=(node){d,fa,1,1,0,0,0};
}
void rot(int x,int w)//左旋:0,右旋:1
{
int y=tr[x].fa,yy=tr[y].fa;
tr[y].son[1^w]=tr[x].son[w];
if(tr[x].son[w]) tr[tr[x].son[w]].fa=y;
tr[yy].son[tr[yy].son[0]==y?0:1]=x;
tr[x].fa=yy,tr[x].son[w]=y,tr[y].fa=x;
ups(y),ups(x);
}
void splay(int x,int rt)
{
while(tr[x].fa!=rt)
{
int y=tr[x].fa,yy=tr[y].fa;
if(yy==rt)
{
rot(x,tr[y].son[0]==x?1:0);
continue;
}
if(tr[yy].son[0]==y)
{
if(tr[y].son[0]==x) rot(y,1),rot(x,1); else rot(x,0),rot(x,1);
continue;
}
if(tr[y].son[1]==x) rot(y,0),rot(x,0); else rot(x,1),rot(x,0);
}
if(!rt) root=x;
}
int findip(int x,int d)
{
if(d==tr[x].d) return x;
if(d<tr[x].d)
return tr[x].son[0]?findip(tr[x].son[0],d):x;
else
return tr[x].son[1]?findip(tr[x].son[1],d):x;
}
void ins(int d)
{
if(!root)
{
add(d,0);
root=1;
return;
}
int u=findip(root,d);
if(tr[u].d==d)
{
tr[u].n++;
ups(u);
splay(u,0);
return;
}
add(d,u);
tr[u].son[d<tr[u].d?0:1]=len;
ups(u);
splay(len,0);
}
int findnum(int x,int d)
{
ups(x);
int lc=tr[x].son[0],rc=tr[x].son[1];
if(d<=tr[lc].c) return findnum(lc,d);
else if(d>tr[lc].c+tr[x].n) return findnum(rc,d-tr[lc].c-tr[x].n);
else return tr[x].d;
}
void work(int x,int y)
{
int t1=findnum(root,x)+1,t2=findnum(root,y+2)+1;
splay(t1,0);
splay(t2,t1);
tr[tr[t2].son[0]].lazy^=1;
}
void dfs(int x)
{
ups(x);
if(tr[x].son[0]) dfs(tr[x].son[0]);
if(x>=2&&x<=n+1) printf("%d ",x-1);
if(tr[x].son[1]) dfs(tr[x].son[1]);
}
int main()
{
int x,y;
scanf("%d %d",&n,&m);
for(int i=0;i<=n+2;i++)
ins(i);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
work(x,y);
}
dfs(root);
}