您的位置:首页 > 理论基础 > 数据结构算法

无比强大的数据结构 伸展树总结

2012-09-30 17:09 357 查看
链接 :http://www.notonlysuccess.com/index.php/splay-tree/

论文链接:http://www.docin.com/p-62465596.html

其实本来不想学splay树的,因为好像平时做题不怎么用到,但是,请注意,书到用时方恨少啊,多一点储备,就多一分机会

论文里说,动态树也要用splay来维护的说,有的斜率优化的题也要用splay来优化,所以,这几天我将我找到的splay的题目刷了下,整理如下

我觉得伸展树的作用应该分为两类,一类主要体现在维护区间的作用上,而另一类则是和普通的平衡树一样

首先介绍一下普通平衡树都有的功能

普通平衡树的功能主要有   

 插入 删除 一个数

 找 前驱  后继  第k大 小

求大于等于或小于等于某个数的个数(可以求逆序数)

确定一个数的排名

我找了一些基本的数据结构题 ,用 treap 和 splay 都实现了下,效率差不多

CSDN代码没有收缩功能,所以就不放这里了

splay的普通平衡树功能 :  模板在这里

下面是splay最重要的功能,对区间各种性质的维护

notonlysuccess的博客里已经有了很详细的介绍和一些习题,我就把做过的题贴上来吧

普通平衡树功能,找第k大,插入删除等    郁闷的出纳员   题解

找前驱 后继 删除一个节点,直接将要删除的节点旋转到根,然后删除根节点即可       宠物收养所:  题解

营业额统计   题解

区间更新,求和,模板题

区间翻转   题解


Queue-jumpers 

  要注意离散化的方法,其他操作对伸展树来说就相当于模拟     题解

区间切割插入     题解

上面的题都做了就可以挑战下下面两个重口味的题目了

poj 3580        这道题会用到伸展树的各种操作,主要是交换两个相邻的区间,直接切割一个区间,然后再插入相应的位置即可  题解

维修数列       这题的最大子列和 和  区间翻转结合起来 制造了一个巨大的坑,如果发现不了,下面这组数据可以告诉你为什么,不过最好还是自己去发现,

维修数列的题解在这里

呵呵,伸展树搞定了,可以开工其他以前可望不可即的数据结构了

伸展树的模板

#include<cstdio>
typedef __int64 lld;
const int inf = ~0u>>2;
#define L ch[x][0]
#define R ch[x][1]
#define KT (ch[ch[rt][1]][0])
const int maxn = 222222;
struct SplayTree{
int ch[maxn][2];
int pre[maxn],sz[maxn],val[maxn];
int rt,top;
void Rotate(int x,int f) {
int y = pre[x];
down(y);   down(x);
ch[y][!f] = ch[x][f];
pre[ ch[x][f] ] = y;
pre[x] = pre[y];
if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] = x;
ch[x][f] = y;
pre[y] = x;
up(y);
}
void Splay(int x,int goal) {
down(x);
while(pre[ x ] != goal ) {
down( pre[pre[x]] ); down( pre[x] ); down(x);
if(pre[ pre[x] ] == goal) Rotate( x , ch[ pre[x] ][0] == x );
else  {
int y = pre[x] ,z = pre[y];
int f = ( ch[z][0] == y);
if(ch[y][f] == x) Rotate( x , !f ),Rotate( x , f );
else 	Rotate( y , f ),Rotate( x , f );
}
}
up(x);
if(goal == 0) rt = x;
}
void RTO(int k,int goal) {
int x=rt;
down(x);
while(sz[ L ] + 1 != k) {
if(k < sz[ L ] + 1)  x = L ;
else {
k -= (sz[ L ] + 1);
x = R;
}
down(x);
}
Splay(x,goal);
}
void vist(int x){
if(x){
printf("结点%2d : 左儿子  %2d   右儿子  %2d  val: %2d sum=%I64d\n",x,ch[x][0],ch[x][1],val[x],sum[x]);
vist(L);
vist(R);
}
}
void debug() {
puts("");	vist(rt);  puts("");
}
void up(int x) {
sz[x] = 1 + sz[ L ] + sz[ R ];
sum[x] = val[x] + sum[ L ] + sum[ R ];
}
void down(int x) {
if(add[x]) {
val[ L ] += add[ x ];
val[ R ] += add[ x ];
add[ L ] += add[ x ];
add[ R ] += add[ x ];
sum[ L ] += (lld)add[x] * sz[ L ];
sum[ R ] += (lld)add[x] * sz[ R ];
add[ x ] = 0;
}
}
void Newnode(int &x,int c,int f) {
x=++top;
L = R  = 0;  sz[x]=1;	pre[x]=f;

val[x] = sum[x] = c;
add[x] = 0;
}

void build(int &x,int l,int r,int f) {
if(l>r) return ;
int m=l+r>>1;
Newnode(x , num[m] , f);
build( L , l , m-1 , x);
build( R , m + 1, r , x);
up(x);
}
void init(int n) {
ch[0][0]=ch[0][1]=pre[0]=0;
sz[0]=rt=top=0;

add[0]=sum[0]=0;

Newnode(rt,-1,0);
Newnode(ch[rt][1],-1,rt);
sz[rt]=2;
for(int i=1;i<=n;i++) scanf("%d",&num[i]);

build(KT,1,n,ch[rt][1]);
up(ch[rt][1]);  up(rt);
}
void update() {
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
RTO(l,0);
RTO(r+2,rt);
add[KT] += c;
val[KT] += c;
sum[KT] += (lld) c * sz[KT];
}
void query() {
int l,r;
scanf("%d%d",&l,&r);
RTO(l,0);
RTO(r+2,rt);
printf("%I64d\n",sum[KT]);
}
lld sum[maxn];
int add[maxn];
int num[maxn];
}spt;
int main() {
int m,n;char op[5];
scanf("%d%d",&n,&m);
spt.init(n);
while(m--) {
scanf("%s",op);
if(op[0]=='Q') spt.query();
else spt.update();
}
return 0;
}
/*
4 10
1 2 3 4
Q 2 4
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息