上次写splay拿noi2015维修数列来练手,当时觉得自己写得还挺好的,但是后来发现那个模板居然不能拿来写LCT(其实应该也可以写的,但是我是蒟蒻,我不会)。所以又发愤图强,去各大神犇博客中学习,终于写出了新的模板。
与之前的不同:
1、设虚节点,可以降低崩溃的几率;
2、旋转和splay等函数不需要打引用;
3、splaying用循环的方式,代替原来递归的方式,省空间。
注意事项:
1、在写build函数时(不只是splay,写指针版线段树这样的东西时也要注意)splay一定要打引用,否则就相当于这棵树没有建;
2、Merge和Split操作最好还是特判一下,虽然有点麻烦,但是就两行;
3、在寻找地址的时候顺便push_down,要不然错误会千奇百怪层出不穷,当然,我们也应该清楚的认识到矛盾具有特殊性,要具体问题具体分析。
模板代码如下:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,l,r;
struct splay{
splay *ch[2],*fa;
int val,sz;
bool flip;
splay(int);
int cmp(int k)
{
if(k<=ch[0]->sz) return 0;
if(k>ch[0]->sz+1) return 1;
return -1;
}
void maintain() {sz=1+ch[0]->sz+ch[1]->sz;}
splay* find_it(int k)
{
push_down();
int d=cmp(k);
if(d==-1) return this;
if(d==1) k-=ch[0]->sz+1;
return ch[d]->find_it(k);
}
void push_down();
int dir();
}*null=new splay(0),*V,*x,*y;
splay :: splay(int x)
{
sz=null?1:0;
val=x;flip=false;
ch[0]=ch[1]=fa=null;
}
void splay :: push_down()
{
if(!flip) return;
flip=false;
swap(ch[0],ch[1]);
if(ch[0]!=null) ch[0]->flip=!ch[0]->flip;
if(ch[1]!=null) ch[1]->flip=!ch[1]->flip;
return;
}
int splay :: dir()
{
return fa->ch[0]==this?0:fa->ch[1]==this?1:-1;
}
void turn(splay *c,int d)
{
splay *y=c->ch[d^1];
c->ch[d^1]=y->ch[d];
if(y->ch[d]!=null) y->ch[d]->fa=c;
y->fa=c->fa;
y->ch[d]=c;
int k;
if(~(k=c->dir())) c->fa->ch[k]=y;
c->fa=y;
c->maintain();
y->maintain();
}
void splaying(splay *c)
{
int d;
while(~(d=c->dir()))
{
if(d==c->fa->dir()) turn(c->fa->fa,d^1);
turn(c->fa,d^1);
}
}
void build(splay *&c,int l,int r)
{
if(l>r) return;
int mid=l+r>>1;
c=new splay(mid);
build(c->ch[0],l,mid-1);
build(c->ch[1],mid+1,r);
if(c->ch[0]!=null) c->ch[0]->fa=c;
if(c->ch[1]!=null) c->ch[1]->fa=c;
c->maintain();
return;
}
splay* Merge(splay *x,splay *y)
{
if(x==null) return y;
if(y==null) return x;
splay *c=x->find_it(x->sz);
splaying(c);
c->ch[1]=y;
y->fa=c;
c->maintain();
return c;
}
void Split(splay *V,splay *&x,splay *&y,int k)
{
if(k<=0) {x=null;y=V;return;}
if(k>=V->sz) {x=V;y=null;return;}
splay *c=V->find_it(k);
splaying(c);
y=c->ch[1];y->fa=null;
x=c; x->ch[1]=null;
x->maintain();
return;
}
void cs(splay *c)
{
if(c==null) return;
c->push_down();
cs(c->ch[0]);
printf("%d ",c->val);
cs(c->ch[1]);
return;
}
int main()
{
scanf("%d%d",&n,&m);
build(V,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
Split(V,V,x,l-1);
Split(x,x,y,r-l+1);
if(x!=null) x->flip=!x->flip;
V=Merge(V,x);
V=Merge(V,y);
}
cs(V);
return 0;
}