本文以【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;
}