您的位置:首页 > 其它

【伸展树splay学习小记】

2016-06-30 08:27 399 查看

本文以【bzoj】【1588】为例

基本操作

splay是基本操作,rotate是splay的基本操作。splay(now,root)把now splay到root的下面。单旋和双旋就不说了。我们可以简化操作,如果是一字型(方向相同)则先旋father,否则先旋now。然后再旋now。

一字型







之字型







故可合并成

void splay(int now,int root){
while(father[now]!=root){
if(father[father[now]]!=root){
if(flag(now)==flag(father[now]))rotate(father[now]);
else rotate(now);
}
rotate(now);
}
}


rotate now是指将now绕father rotate。有两个方向,表示now是father的左儿子还是右儿子。

bool flag(int now){
return son[father[now]][1]==now;
}


通过方向标记,我们可以将两个方向的rotate合成一个。

void rotate(int now){
int fa=father[now],fx=flag(now);
son[fa][fx]=son[now][!fx];
if(son[now][!fx])father[son[now][!fx]]=fa;
//连接father和son[now]
son[father[fa]][flag(fa)]=now;
father[now]=father[fa];
//连接grandpa和now
son[now][!fx]=fa;
father[fa]=now;
//连接now和father
updata(fa);updata(now);
}


具体步骤请自行脑补。

别忘了rotate完成后要updata。

void updata(int pos){
size[pos]=size[son[pos][0]]+size[son[pos][1]]+1;
}


寻找k小值的标号

int kth(int now,int th){
if(size[son[now][0]]+1==th)return now;
else if(size[son[now][0]]+1>th)return kth(son[now][0],th);
else return kth(son[now][1],th-size[son[now][0]]-1);
}


寻找前驱

int pre(int val){
int tmp=kth(son[val][0],size[son[val][0]]);
splay(tmp,val);
return key[tmp];
}


寻找后继

int succ(int val){
int tmp=kth(son[val][1],1);
splay(tmp,val);
return key[tmp];
}


插入

首先要找到一个合适的位置

int getpos(int now,int val){
if((key[now]<val)&&(size[son[now][1]]))return getpos(son[now][1],val);
else if((key[now]>val)&&(size[son[now][0]]))return getpos(son[now][0],val);
return now;
}


但是我们并不能保证这个点是大于还是小于插入节点

void insert(int root,int pos,int val){
int sroot=father[root];
splay(root=getpos(root,val),sroot);
if(key[root]<val){
succ(root);//十分重要
rotate(root=son[root][1]);
}
int tmp=son[root][0];key[pos]=val;
son[root][0]=pos;father[pos]=root;
son[pos][0]=tmp;father[tmp]=pos;
updata(pos);updata(root);
splay(pos,0);
}


我们把刚好比插入点大的点作为根,在左子树插入。如果根小于插入点,则要将根的后继变成根(!!!注意不是根的右儿子!!!)

至此splay的基本操作我们都完成了。

更新:

ps

对于有重复元素的题,我们必须小心小心再小心。find的时候必须找最小序号的哪一个,pre和succ查询的数可能不在splay中,要做一点处理。

删除

void dele(int root,int val){
int sroot=father[root];
splay(root=find(root,val),sroot);
if(son[root][1])splay(succ(root),root);
son[sroot][flag(root)]=son[root][1];
father[son[root][1]]=sroot;
son[son[root][1]][0]=son[root][0];
father[son[root][0]]=son[root][1];
updata(son[root][1]);
}


查找标号

int rank(int now,int val){
if(key[now]==val)return size[son[now][0]]+1;
else if(val<key[now])return rank(son[now][0],val);
else if(val>key[now])return size[son[now][0]]+1+rank(son[now][1],val);
}


另外一个查找

int find(int now,int val){//pos
if(mx[son[now][0]]>=val)return find(son[now][0],val);
if(key[now]==val)return now;
if(mi[son[now][1]]<=val)return find(son[now][1],val);
return now;
}


【bzoj】【1588】【code】

#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=1000000,inf=2147483647;
int n,size[maxn+10],key[maxn+10],father[maxn+10],son[maxn+10][10];
void updata(int pos){ size[pos]=size[son[pos][0]]+size[son[pos][1]]+1; }
bool flag(int now){ return son[father[now]][1]==now; }
void rotate(int now){
int fa=father[now],fx=flag(now);
son[fa][fx]=son[now][!fx];
if(son[now][!fx])father[son[now][!fx]]=fa;
son[father[fa]][flag(fa)]=now;
father[now]=father[fa];
son[now][!fx]=fa;
father[fa]=now;
updata(fa);updata(now);
}
void splay(int now,int root){ while(father[now]!=root){ if(father[father[now]]!=root){ if(flag(now)==flag(father[now]))rotate(father[now]); else rotate(now); } rotate(now); } }
int getpos(int now,int val){ if((key[now]<val)&&(size[son[now][1]]))return getpos(son[now][1],val); else if((key[now]>val)&&(size[son[now][0]]))return getpos(son[now][0],val); return now; }
int kth(int now,int th){ if(size[son[now][0]]+1==th)return now; else if(size[son[now][0]]+1>th)return kth(son[now][0],th); else return kth(son[now][1],th-size[son[now][0]]-1); }
int pre(int val){ int tmp=kth(son[val][0],size[son[val][0]]); splay(tmp,val); return key[tmp]; }
int succ(int val){ int tmp=kth(son[val][1],1); splay(tmp,val); return key[tmp]; }
void insert(int root,int pos,int val){
int sroot=father[root];
splay(root=getpos(root,val),sroot);
if(key[root]<val){
succ(root);
rotate(root=son[root][1]);
}
int tmp=son[root][0];key[pos]=val;
son[root][0]=pos;father[pos]=root;
son[pos][0]=tmp;father[tmp]=pos;
updata(pos);updata(root);
splay(pos,0);
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d",&n);
key[n+1]=-inf/2;key[n+2]=inf/2;
size[n+1]=size[n+2]=1;
son[0][1]=n+2;father[n+2]=0;
son[n+2][0]=n+1;father[n+1]=n+2;
int ans=0;
fo(i,1,n){
int x;scanf("%d",&x);
insert(son[0][1],i,x);
if(i==1)ans+=x;
else ans+=min(x-pre(i),succ(i)-x);
printf("%d\n",ans);
}
printf("%d\n",ans);
return 0;
}


【bzoj】【3224】【Tyvj】【1728】【普通平衡树】

#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=100000,inf=2147483647;
int n,key[maxn+10],mx[maxn+10],mi[maxn+10],size[maxn+10],father[maxn+10],son[maxn+10][10];
bool flag(int now){ return son[father[now]][1]==now; }
void updata(int now){
size[now]=size[son[now][0]]+size[son[now][1]]+1;
mx[now]=max(key[now],max(mx[son[now][0]],mx[son[now][1]]));
mi[now]=min(key[now],min(mi[son[now][0]],mi[son[now][1]]));
}
void rotate(int now){
int fa=father[now],fx=flag(now);
son[fa][fx]=son[now][!fx];
if(son[now][!fx])father[son[now][!fx]]=fa;
son[father[fa]][flag(fa)]=now;
father[now]=father[fa];
son[now][!fx]=fa;
father[fa]=now;
updata(fa);updata(now);
}
void splay(int now,int root){
while(father[now]!=root){
if(father[father[now]]!=root)
if(flag(now)==flag(father[now]))rotate(father[now]);else rotate(now);
rotate(now);
}
}
int find(int now,int val){//pos if(mx[son[now][0]]>=val)return find(son[now][0],val); if(key[now]==val)return now; if(mi[son[now][1]]<=val)return find(son[now][1],val); return now; }
int kth(int now,int val){//pos
if(size[son[now][0]]+1==val)return now;
else if(val<size[son[now][0]]+1)return kth(son[now][0],val);
else return kth(son[now][1],val-size[son[now][0]]-1);
}
int succ(int now){//pos
int tmp=kth(son[now][1],1);
splay(tmp,now);
return tmp;
}
void insert(int root,int pos,int val){
int sroot=father[root];
splay(root=find(root,val),sroot);
if(key[root]<val){
splay(succ(root),root);
rotate(root=son[root][1]);
}
key[pos]=val;int tmp=son[root][0];
son[root][0]=pos;father[pos]=root;
son[pos][0]=tmp;father[tmp]=pos;
updata(pos);updata(root);
}
int pre(int now){//pos
int tmp=kth(son[now][0],size[son[now][0]]);
splay(tmp,now);
return tmp;
}
void dele(int root,int val){ int sroot=father[root]; splay(root=find(root,val),sroot); if(son[root][1])splay(succ(root),root); son[sroot][flag(root)]=son[root][1]; father[son[root][1]]=sroot; son[son[root][1]][0]=son[root][0]; father[son[root][0]]=son[root][1]; updata(son[root][1]); }
int rank(int now,int val){ if(key[now]==val)return size[son[now][0]]+1; else if(val<key[now])return rank(son[now][0],val); else if(val>key[now])return size[son[now][0]]+1+rank(son[now][1],val); }
int main(){
//freopen("d.in","r",stdin);
//freopen("d.out","w",stdout);
freopen("input9.in","r",stdin);
freopen("input9+.out","w",stdout);
scanf("%d",&n);
mx[0]=-inf/2;mi[0]=inf/2;
size[n+1]=size[n+2]=1;
key[n+1]=-inf/2;key[n+2]=inf/2;
son[0][1]=n+2;father[n+2]=0;
son[n+2][0]=n+1;father[n+1]=n+2;
fo(i,1,n){
int opt,x;scanf("%d%d",&opt,&x);
if(opt==1)insert(son[0][1],i,x);
else if(opt==2)dele(son[0][1],x);
else if(opt==3){
int tmp=find(son[0][1],x);splay(tmp,0);
printf("%d\n",size[son[tmp][0]]);
}
else if(opt==4){
int tmp=kth(son[0][1],x+1);splay(tmp,0);
printf("%d\n",key[tmp]);
}
else if(opt==5){
int tmp=find(son[0][1],x);splay(tmp,0);
if(key[tmp]>=x)printf("%d\n",key[pre(tmp)]);
else printf("%d\n",key[tmp]);
}
else{
int tmp=find(son[0][1],x+1);splay(tmp,0);
if(key[tmp]<=x)printf("%d\n",key[succ(tmp)]);
else printf("%d\n",key[tmp]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: