splay小归纳
感觉splay就是一个根据中序遍历维护序列并提取信息的二叉树,根据旋转尽量维护二叉树的平衡并进行各类修改操作
splay应该有如下几个操作:
左右旋
作用是把当前节点提拉到它父节点的位置,并满足整棵splay的中序遍历不变
目的是将当前splay转换成等效的但更便于操作的splay
事实上左旋和右旋应该是不一样的,但由于打代码时分开打比较繁琐,直接合并也无伤大雅
代码(合并):
inline void rotate(int x){
int fa=f[x],grand=f[f[x]],le=blood(x);
f[x]=grand;
if(grand)ch[grand][blood(fa)]=x;
ch[fa][le]=ch[x][le^1];
f[ch[fa][le]]=fa;
f[fa]=x;
ch[x][le^1]=fa;
update(fa);update(x);
return ;
}
splay
作用同左右旋
目的同左右旋
一次splay就是多个左右旋加在一起
代码:
inline void splay(int x){
for(int fa;(fa=f[x]);rotate(x))
if(f[f[x]])
rotate(blood(x)==blood(f[x])?f[x]:x);
root=x;
return ;
}
查找
作用是找到当前第k项或着是权值为k的元素的编号
目的一般是满足题目的查找操作,或是辅助其他操作
代码(查找第k项):
int find(int x){
//del(low-ex);
int now=root;
while(1){
if(ch[now][0]&&x<=size[ch[now][0]]){now=ch[now][0];continue;}
if(ch[now][0])x-=size[ch[now][0]];
x-=tot[now];
if(x<=0) return data[now];
now=ch[now][1];
}
puts("ERROR IN FIND");
return -32767;
}
代码(查找权值为k的元素编号,并提至根节点):
inline void find(int x){
if(!root)return ;
int now=root;
while(tr[now].ch[x>tr[now].val]&&x!=tr[now].val)now=tr[now].ch[x>tr[now].val];
splay(now,0);
return ;
}
求前驱&后驱
作用是找到当前节点在序列上的(前/后)一个节点
目的很随意,这个操作可以搞很多事
代码:
inline int nxt(int x,int leaf){
splay(x,0);
find(x);
int now=root;
if(leaf&&tr[now].val>x)return now;
if(!leaf&&tr[now].val<x)return now;
now=tr[now].ch[leaf];
while(tr[now].ch[leaf^1])now=tr[now].ch[leaf^1];
return now;
}
还有很多组合操作,如:
插入节点
查找+建立父子关系
代码
inline void insert(int x){
int now=root,f=0;
while(now&&tr[now].val!=x){
f=now;
now=tr[now].ch[x>tr[now].val];
}
if(now)++tr[now].cnt;
else{
now=++sz;
if(f)tr[f].ch[x>tr[f].val]=now;
tr[now].ch[0]=tr[now].ch[1]=0;
tr[now].f=f,tr[now].val=x;
tr[now].cnt=1;tr[now].size=1;
}
splay(now,0);
return ;
}
删除节点
查找+splay+解除父子关系
代码
inline void del(int x){
int fr=nxt(x,0),Ba=nxt(x,1);
splay(fr,0);splay(Ba,fr);
if(tr[tr[Ba].ch[0]].cnt>1){
--tr[tr[Ba].ch[0]].cnt;
splay(tr[Ba].ch[0],0);
}
else
tr[Ba].ch[0]=0;
return ;
}
还有一些附加操作,如:
区间操作
主体思想就是打lazy标识
然而为了找到操作区间[l,r],需要找到l的前驱和r的后驱,将l-1转到根节点,将r+1结点转到根节点的右儿子,则以根节点的右儿子的左儿子为根的子树即为目标操作区间,易证
代码(以文艺平衡树为例):
#include<bits/stdc++.h>
using namespace std;
#define blood(x) (ch[f[(x)]][1]==(x))
#define cl(x) memset(x,0,sizeof(x))
#define cl1(x) memset(x,-1,sizeof(x))
#define rg register
#define oo 0x3f3f3f3f
#define inf 0x7fffffff
template <typename _Tp> inline void read(_Tp&x){
char c11=getchar();x=0;bool booo=0;
while(c11!='-'&&!isdigit(c11))c11=getchar();if(c11=='-'){c11=getchar();booo=1;}
while(isdigit(c11)){x=x*10+c11-'0';c11=getchar();}if(booo)x=-x;return ;
}
const int N=105000;
int ch[N][2],f[N],delta[N],size[N],key[N],a[N];
int sz=0,root=0;
int n,m;
inline void update(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+1;}
inline void pushdown(int x){
if(x&&delta[x]){
delta[ch[x][0]]^=1;
delta[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
delta[x]=0;
}
return ;
}
inline int build(int,int,int);
inline int find(int);
inline void print(int now);
inline void rotate(int x){
pushdown(f[x]);
pushdown(x);
int daddy=f[x],grand=f[f[x]],cho=blood(x);
ch[daddy][cho]=ch[x][cho^1];
f[ch[daddy][cho]]=daddy;
ch[x][cho^1]=daddy;
f[daddy]=x;
f[x]=grand;
if(grand)
ch[grand][ch[grand][1]==daddy]=x;
update(daddy);
update(x);
return ;
}
inline void splay(int x,int target){
for(rg int fa;(fa=f[x])!=target;rotate(x))
if(f[fa]!=target)
rotate(blood(x)==blood(fa)?fa:x);
if(target==0)root=x;
return ;
}
int main(){
freopen("in","r",stdin);
read(n);read(m);
a[1]=-oo,a[n+2]=+oo;
for(rg int i=1;i<=n;++i)a[i+1]=i;
root=build(1,n+2,0);
int x,y;
while(m--){
read(x);read(y);
int aa=find(x),bb=find(y+2);
splay(aa,0);splay(bb,aa);
delta[ch[ch[root][1]][0]]^=1;
}
print(root);
return 0;
}
inline int find(int x){
int now=root;
while("%%% boshi %%%"){
pushdown(now);
if(x<=size[ch[now][0]])
now=ch[now][0];
else{
x-=size[ch[now][0]]+1;
if(!x)return now;
now=ch[now][1];
}
}
return -32767;
}
inline int build(int l,int r,int fa){
if(l>r)return 0;
int mid=(l+r)>>1;
int now=++sz;
key[now]=a[mid],f[now]=fa,delta[now]=0;
ch[now][0]=build(l,mid-1,now);
ch[now][1]=build(mid+1,r,now);
update(now);
return now;
}
inline void print(int now){
pushdown(now);
if(ch[now][0])print(ch[now][0]);
if(key[now]!=-oo&&key[now]!=+oo)
printf("%d ",key[now]);
if(ch[now][1])print(ch[now][1]);
return ;
}
2017年最后一天,祝各位神犇在新的一年里拿省一,进省队,拿Au,签清北