上周学了AVl平衡树,作为一个好学生,坚持不copy,每次都从空文件开始写的我感觉AVl代码真的是太,,,长了。
这周一来老师就讲了splay,给了一种很巧妙的简洁写法,个人感觉非常好,并且不容易写错,没这么多细节注意。(手残的人尤其开心)
splay的操作跟avl很像,只是基础操作单位和操作顺序不同。
这道题是splay的基础题,也是很典型的不用AVl树做的题目(因为要保持平衡,AVl显得太过于繁复了)
对于CUT操作:
将当前树上第a-1个结点转到根结点,然后把第b+1个结点转到根结点的右儿子处,
于是root的右儿子的左儿子就是要删除区间的根,直接赋0就好
将c转到根结点,此时树被分成第1~第c的树A,和c的右子树B
将[a,b]这棵树接在第1~第c的右子结点上,
然后在新的树上找到最靠右的结点将c的右子树B结在它的右子结点上
对于Flip操作:
将当前树上第a-1个结点转到根结点,然后把第b+1个结点转到根结点的右儿子处,
于是root的右儿子的左儿子就是要要翻转的区间的根,
懒标记给此时root的右儿子的左儿子就好,
然后注意在所有的向下操作中都要pushdown(),即懒标记下传(这地方线段树的题体现得尤为明显)
写在代码前面:
为了防止出现一些不必要的诡异事件,我在树中加了两个虚拟结点(一个是-1,一个是N+1)方便调试
所以在调用找排名的函数时会将排名全部+1变成a和b+2,这并不是与我之前的分析相违背的
还有,如果直接建树会出现一条链,导致不够优化,所以此处我二分建树了。
呃呃。。它确实是跑得死慢死慢的。。。
20193787 | 2017-03-21 20:49:22 | Accepted | 3487 | 873MS | 8624K | 3521 B | G++ |
#include
#include
using namespace std;
const int Max=300000;
int N,M,root,cnt;
bool flag;
int ch[Max+5][2],fa[Max+5],fli[Max+5],num[Max+5],sz[Max+5];
void getint(int &num){
char c;int flag=1;num=0;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
num*=flag;
}
void change(int r){
if(!r)return ;
fli[r]^=1;
}
void pushup(int r){
if(!r)return ;
sz[r]=sz[ch[r][0]]+sz[ch[r][1]]+1;
}
void pushdown(int r){
if(r&&fli[r]){
swap(ch[r][0],ch[r][1]);
change(ch[r][0]);
change(ch[r][1]);
change(r);
}
}
void rotato(int x){
if(!x||!fa[x])return ;
int y=fa[x],z=fa[y];
pushdown(y),pushdown(x);
bool flag=(ch[y][1]==x);
ch[y][flag]=ch[x][!flag];
if(ch[x][!flag]) fa[ch[x][!flag]]=y;
ch[x][!flag]=y,fa[y]=x;
fa[x]=z;
if(z) ch[z][ch[z][1]==y]=x;
pushup(y),pushup(x);
}
void splay(int x,int goal){
for(int y; (y=fa[x])!=goal; rotato(x)){
int z=fa[y];
if(z!=goal){
if((ch[y][1]==x)==(ch[z][1]==y))
rotato(y);
else rotato(x);
}
}
if(goal==0) root=x;
}
void newtr(int &r,int f,int val){
r=++cnt;
fa[r]=f,sz[r]=1;
num[r]=val;
ch[r][0]=ch[r][1]=fli[r]=0;
}
void build(int &rt,int l,int r,int f){
if(l>r)return ;
int mid=(l+r)>>1;
newtr(rt,f,mid);
build(ch[rt][0],l,mid-1,rt);
build(ch[rt][1],mid+1,r,rt);
pushup(rt);
}
void Tr_build(){
root=cnt=ch[0][0]=ch[0][1]=sz[0]=fa[0]=fli[0]=0;
newtr(root,0,-1);
newtr(ch[root][1],root,N+1);
build(ch[ch[root][1]][0],1,N,ch[root][1]);
pushup(ch[root][1]);
pushup(root);
}
void Tr_merge(int root1,int root2){
ch[root1][1]=root2;
fa[root2]=root1;
}
int find_rank(int r,int rank){
pushdown(r);
int t=sz[ch[r][0]]+1;
if(t==rank)return r;
if(t>rank) return find_rank(ch[r][0],rank);
return find_rank(ch[r][1],rank-t);
}
int find_max(int r){
pushdown(r);
while(ch[r][1])
r=ch[r][1],pushdown(r);
return r;
}
void CUT(int a,int b,int c){
int x=find_rank(root,a),z;
splay(x,0);
x=find_rank(root,b+2);
splay(x,root);
int root1=ch[ch[root][1]][0];
ch[ch[root][1]][0]=0;
pushup(ch[root][1]);
pushup(root);
z=find_rank(root,c+1);
splay(z,0);
int root2=ch[root][1];
Tr_merge(root,root1);
pushup(root);
splay(find_max(root),0);
Tr_merge(root,root2);
pushup(root);
}
void Flip(int a,int b){
splay(find_rank(root,a),0);
splay(find_rank(root,b+2),root);
change(ch[ch[root][1]][0]);
}
void print(int r){
if(!ch[r][0]&&!ch[r][1]){
if(num[r]!=-1&&num[r]!=N+1){
if(flag)putchar(32);
printf("%d",num[r]);
flag=1;
}
return ;
}
pushdown(r);
if(ch[r][0])print(ch[r][0]);
if(num[r]!=-1&&num[r]!=N+1){
if(flag)putchar(32);
printf("%d",num[r]);flag=1;
}
if(ch[r][1])print(ch[r][1]);
}
int main(){
char ord[5];
int a,b,c;
while(~scanf("%d%d",&N,&M)&&N!=-1&&M!=-1){
Tr_build();
for(int i=1; i<=M; ++i){
scanf("%s",ord);
getint(a),getint(b);
if(ord[0]=='C'){
getint(c);
CUT(a,b,c);
}
else Flip(a,b);
}
flag=0;
print(root);
putchar(10);
}
return 0;
}