//本文是一个暂时的小记,有不对的请大佬们指出~
真正大佬的在这http://blog.csdn.net/clove_unique/article/details/50630280
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由丹尼尔·斯立特Daniel Sleator和罗伯特·恩卓·塔扬Robert Endre Tarjan在1985年发明的。
在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法, 在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。伸展树应运而生。伸展树是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。
它的优势在于不需要记录用于平衡树的冗余信息。
(本段来自百度)
Splay的基本操作
- get操作
主要用来查找x结点属于其父亲结点的左儿子还是右儿子
int get(int x)
{
return son[fa[x]][1]==x;
}
- update操作
主要是更新size值
(有的时候也会更新其他)
void update(int x)
{
if (x)
{
size[x]=1;
if (son[x][0]) size[x]+=size[son[x][0]];
if (son[x][1]) size[x]+=size[son[x][1]];
}
}
- rotate(旋转)操作
这是Splay最常用也是最重要的操作了
主要将x结点向上转一下
例如:
然后我们把结点5向上旋转一下,转到3的位置
具体的操作就是找到x与父亲的关系(是他的左儿子还是右儿子),然后旋上去,直接取代其父亲的位置,然后进行一系列的“儿子认领“(具体看代码)
int rotate(int x)
{
int k=get(x),y=fa[x];
if(fa[y])son[fa[y]][get(y)]=x;
if(son[x][!k])fa[son[x][!k]]=y;//x结点反方向的儿子
fa[x]=fa[y],fa[y]=x,son[y][k]=son[x][!k],son[x][!k]=y;//认领儿子
update(y),update(x);
}
然后来一道例题,相信用线段树做过【最大值】,此题甚好,但是又有了区间修改,变成了【最大值2】,现在用Splay实现:
题目不记得了吧~
Description
在N(1<=N<=100000)个数A1…An组成的序列上进行M(1<=M<=100000)次操作,操作有两种:
(1)1 L R C:表示把A[L]到A[R]增加C(C的绝对值不超过10000);
(2)2 L R:询问A[L]到A[R]之间的最大值。
思考一下~
好的,那么我们只需要在上面讲的所有里面加入一个打标记的操作就好了。
这和线段树的差不多,打完这个标记lazy,下传~
#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
int son[100001][2];//Son
LL fmax[100001];//Ans
int fa[100001];//Father
LL add[100001];//Lazy
LL a[100001];//Data
int d[100001];//Queue
int n,m,kind,l,r,c;
int update(int x){fmax[x]=max(a[x],max(fmax[son[x][0]],fmax[son[x][1]]));}
int lazy(int x,int c){fmax[x]+=c,a[x]+=c,add[x]+=c;}
int get(int x){return son[fa[x]][1]==x;}
int clear(int x)
{
if(son[x][0])lazy(son[x][0],add[x]);
if(son[x][1])lazy(son[x][1],add[x]);
add[x]=0;
}
int remove(int x,int y)
{
d[0]=0;
for (x=x;x-y;x=fa[x]) d[++d[0]]=x;
while (d[0]) clear(d[d[0]--]);
}
int rotate(int x)
{
int k=get(x),y=fa[x];
if(fa[y])son[fa[y]][get(y)]=x;
if(son[x][!k])fa[son[x][!k]]=y;
fa[x]=fa[y],fa[y]=x,son[y][k]=son[x][!k],son[x][!k]=y;
update(y),update(x);
}
int Splay(int x,int y)
{
remove(x,y);
while(fa[x]-y)
{
if(fa[fa[x]]-y)
if(get(x)==get(fa[x])) rotate(fa[x]);
else rotate(x);
rotate(x);
}
}
int main()
{
freopen("Max2.in","r",stdin);
scanf("%d",&n);
int i;fmax[0]=-1e9;
for (i=1;i<=n;++i)
scanf("%lld",&a[i+1]),fa[i]=i+1,son[i+1][0]=i,update(i+1);
fa[n+1]=n+2,son[n+2][0]=n+1,update(n+2);
scanf("%d",&m);
for (i=1;i<=m;++i)
{
scanf("%d%d%d",&kind,&l,&r);++l,++r;
Splay(l-1,0),Splay(r+1,l-1);
if(kind-2){scanf("%d",&c),lazy(son[r+1][0],c);}
else printf("%lld\n",fmax[son[r+1][0]]);
}
}