【伸展树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;
}
相关文章推荐
- 注解开发--基础
- iOS 开发中的争议(二)
- 【bzoj1588】【HNOI2002】【营业额统计】【splay】
- mysql+hibernate 一些报错
- 第三方的使用
- iOS 开发中的争议(一)
- Hourai Jeweled
- JavaScript中的匿名函数及函数的闭包
- iOS APP可执行文件的组成
- 一篇搞定RSA加密与SHA签名|与Java完全同步
- linux——深入理解linux内存分布—基础篇
- noip2009靶形数独(优化搜索顺序+位运算(只是常数优化,快一点))
- TimesTen的逻辑服务器名概念
- 刷单软件,刷单平台,手机刷单
- Arcgis属性转CAD注记,添加CAD字段实现快速分层
- 使用cx_Freeze 将python3代码打包成.exe程序
- Javascript模块化编程(二):AMD规范
- Javascript前端模块化
- 无线调制方式简介
- 云主机服务器centos搭建PHP开发环境