类别:二叉排序树

空间效率:O(n)

时间效率:O(log n)内完成插入、查找、删除操作

创造者:Daniel Sleator和Robert Tarjan
优点:每次查询会调整树的结构,使被查询频率高的条目更靠近树根。

伸展树的另一个好处是将最近搜索的节点放在最容易搜索的根节点的位置。在许多应用环境中,比如网络应用中,某些固定内容会被大量重复访问(比如江南style的MV)。伸展树可以让这种重复搜索以很高的效率完成。

注:所有图片来自wiki。
http://blog.csdn.net/cyberzhg/article/details/8058208

Tree Rotation



树的旋转是splay的基础,对于二叉查找树来说,树的旋转不破坏查找树的结构。

Splaying


Splaying是Splay Tree中的基本操作,为了让被查询的条目更接近树根,Splay Tree使用了树的旋转操作,同时保证二叉排序树的性质不变。
Splaying的操作受以下三种因素影响:
  • 节点x是父节点p的左孩子还是右孩子
  • 节点p是不是根节点,如果不是
  • 节点p是父节点g的左孩子还是右孩子
同时有三种基本操作:

Zig Step




当p为根节点时,进行zip step操作。
当x是p的左孩子时,对x右旋;
当x是p的右孩子时,对x左旋。

Zig-Zig Step


当p不是根节点,且x和p同为左孩子或右孩子时进行Zig-Zig操作。
当x和p同为左孩子时,依次将p和x右旋;
当x和p同为右孩子时,依次将p和x左旋。


Zig-Zag Step


当p不是根节点,且x和p不同为左孩子或右孩子时,进行Zig-Zag操作。
当p为左孩子,x为右孩子时,将x左旋后再右旋。
当p为右孩子,x为左孩子时,将x右旋后再左旋。


应用


Splay Tree可以方便的解决一些区间问题,根据不同形状二叉树先序遍历结果不变的特性,可以将区间按顺序建二叉查找树。
每次自下而上的一套splay都可以将x移动到根节点的位置,利用这个特性,可以方便的利用Lazy的思想进行区间操作。
对于每个节点记录size,代表子树中节点的数目,这样就可以很方便地查找区间中的第k小或第k大元素。
对于一段要处理的区间[x, y],首先splay x-1到root,再splay y+1到root的右孩子,这时root的右孩子的左孩子对应子树就是整个区间。
这样,大部分区间问题都可以很方便的解决,操作同样也适用于一个或多个条目的添加或删除,和区间的移动。



POJ2764 Feed the dogs

http://poj.org/problem?id=2764

http://blog.csdn.net/cyberzhg/article/details/8058154



区间不会重叠,所以不可能有首首相同或尾尾相同的情况,读入所有区间,按照右端由小到大排序。然后通过维护splay进行第k小元素的查询操作。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
const int MAXM = 100005;
const int INF = 0x7fffffff;  

class SplayTree
{
public:
    SplayTree()
    {
        nil.size = 0;
        nil.value = INF;
        nil.min = INF;
        nil.lchild = &nil;
        nil.rchild = &nil;
        nil.parent = &nil;
    }  

    inline void make(int array[], int n)
    {
        nodeNumber = 0;
        int mid = (n - 1) >> 1;
        root = newNode(&nil, array[mid]);
        root->lchild = make(0, mid - 1, root, array);
        root->rchild = make(mid + 1, n - 1, root, array);
        update(root);
    }  

    inline void ADD(int x, int y, int D)
    {
        find(x, &nil);
        find(y + 2, root);
        root->rchild->lchild->lazy += D;
    }  

    inline void REVERSE(int x, int y)
    {
        find(x, &nil);
        find(y + 2, root);
        root->rchild->lchild->isReverse ^= true;
    }  

    inline void REVOLVE(int x, int y, int T)
    {
        int len = y - x + 1;
        T = ((T % len) + len) % len;
        if(T)
        {
            find(y - T + 1, &nil);
            find(y + 2, root);
            SplayNode *d = root->rchild->lchild;
            root->rchild->lchild = &nil;
            find(x, &nil);
            find(x + 1, root);
            root->rchild->lchild = d;
            d->parent = root->rchild;
        }
    }  

    inline void INSERT(int x, int P)
    {
        find(x + 1, &nil);
        find(x + 2, root);
        root->rchild->lchild = newNode(root->rchild, P);
    }  

    inline void DELETE(int x)
    {
        find(x, &nil);
        find(x + 2, root);
        root->rchild->lchild = &nil;
    }  

    inline void MIN(int x, int y)
    {
        find(x, &nil);
        find(y + 2, root);
        pushdown(root->rchild->lchild);
        printf("%d\n", root->rchild->lchild->min);
    }  

    inline void print()
    {
        printf("Splay Linear: \n");
        print(root);
        printf("\n");
    }  

    inline void prints()
    {
        printf("Splay Structure: \n");
        prints(root);
        printf("\n");
    }  

private:
    struct SplayNode
    {
        int value, size, lazy;
        SplayNode *parent, *lchild, *rchild;
        int min;
        bool isReverse;
    } nil, node[MAXN + MAXM];
    int nodeNumber;
    SplayNode *root;  

    inline SplayNode *newNode(SplayNode *parent, const int value)
    {
        node[nodeNumber].value = value;
        node[nodeNumber].size = 1;
        node[nodeNumber].lazy = 0;
        node[nodeNumber].parent = parent;
        node[nodeNumber].lchild = &nil;
        node[nodeNumber].rchild = &nil;
        node[nodeNumber].min = value;
        node[nodeNumber].isReverse = false;
        return &node[nodeNumber++];
    }  

    SplayNode *make(int l, int r, SplayNode *parent, int array[])
    {
        if(l > r)
        {
            return &nil;
        }
        int mid = (l + r) >> 1;
        SplayNode *x = newNode(parent, array[mid]);
        x->lchild = make(l, mid - 1, x, array);
        x->rchild = make(mid + 1, r, x, array);
        update(x);
        return x;
    }  

    inline void update(SplayNode *x)
    {
        if(x == &nil)
        {
            return;
        }
        x->size = x->lchild->size + x->rchild->size + 1;
        x->min = min(x->value, min(x->lchild->min, x->rchild->min));
    }  

    inline void pushdown(SplayNode *x)
    {
        if(x == &nil)
        {
            return;
        }
        if(x->isReverse)
        {
            swap(x->lchild, x->rchild);
            x->lchild->isReverse ^= true;
            x->rchild->isReverse ^= true;
            x->isReverse = false;
        }
        if(x->lazy)
        {
            x->value += x->lazy;
            x->min += x->lazy;
            x->lchild->lazy += x->lazy;
            x->rchild->lazy += x->lazy;
            x->lazy = 0;
        }
    }  

    inline void rotateLeft(SplayNode *x)
    {
        SplayNode *p = x->parent;
        pushdown(x->lchild);
        pushdown(x->rchild);
        pushdown(p->lchild);
        p->rchild = x->lchild;
        p->rchild->parent = p;
        x->lchild = p;
        x->parent = p->parent;
        if(p->parent->lchild == p)
        {
            p->parent->lchild = x;
        }
        else
        {
            p->parent->rchild = x;
        }
        p->parent = x;
        update(p);
        update(x);
        if(root == p)
        {
            root = x;
        }
    }  

    inline void rotateRight(SplayNode *x)
    {
        SplayNode *p = x->parent;
        pushdown(x->lchild);
        pushdown(x->rchild);
        pushdown(p->rchild);
        p->lchild = x->rchild;
        p->lchild->parent = p;
        x->rchild = p;
        x->parent = p->parent;
        if(p->parent->lchild == p)
        {
            p->parent->lchild = x;
        }
        else
        {
            p->parent->rchild = x;
        }
        p->parent = x;
        update(p);
        update(x);
        if(root == p)
        {
            root = x;
        }
    }  

    inline void splay(SplayNode *x, SplayNode *y)
    {
        pushdown(x);
        while(x->parent != y)
        {
            if(x->parent->parent == y)
            {
                if(x->parent->lchild == x)
                {
                    rotateRight(x);
                }
                else
                {
                    rotateLeft(x);
                }
            }
            else if(x->parent->parent->lchild == x->parent)
            {
                if(x->parent->lchild == x)
                {
                    rotateRight(x->parent);
                    rotateRight(x);
                }
                else
                {
                    rotateLeft(x);
                    rotateRight(x);
                }
            }
            else
            {
                if(x->parent->rchild == x)
                {
                    rotateLeft(x->parent);
                    rotateLeft(x);
                }
                else
                {
                    rotateRight(x);
                    rotateLeft(x);
                }
            }
        }
        update(x);
    }  

    inline void find(int k, SplayNode *y)
    {
        SplayNode *x = root;
        pushdown(x);
        while(k != x->lchild->size + 1)
        {
            if(k <= x->lchild->size)
            {
                x = x->lchild;
            }
            else
            {
                k -= x->lchild->size + 1;
                x = x->rchild;
            }
            pushdown(x);
        }
        splay(x, y);
    }  

    inline void print(SplayNode *x)
    {
        if(x == &nil)
        {
            return;
        }
        pushdown(x);
        print(x->lchild);
        printf("%d: %d %d %d %d\n", x->value, x->min, x->parent->value, x->lchild->value, x->rchild->value);
        print(x->rchild);
    }  

    inline void prints(SplayNode *x)
    {
        if(x == &nil)
        {
            return;
        }
        pushdown(x);
        if(x->value == INF)
        {
            printf("INF : ");
        }
        else
        {
            printf("%d : ", x->value);
        }
        if(x->lchild == &nil)
        {
            printf("nil ");
        }
        else
        {
            if(x->lchild->value == INF)
            {
                printf("INF ");
            }
            else
            {
                printf("%d ", x->lchild->value);
            }
        }
        if(x->rchild == &nil)
        {
            printf("nil\n");
        }
        else
        {
            if(x->rchild->value == INF)
            {
                printf("INF\n");
            }
            else
            {
                printf("%d\n", x->rchild->value);
            }
        }
        prints(x->lchild);
        prints(x->rchild);
    }
} splayTree;  

char buffer[128];int array[MAXN];int n, m;  

int main()
{
    int x, y, D, T, P;
    scanf("%d", &n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d", &array[i]);
    }
    array[0] = INF;
    array[n+1] = INF;
    splayTree.make(array, n + 2);
    scanf("%d", &m);
    while(m--)
    {
        scanf("%s", buffer);
        switch(buffer[0])
        {
        case 'A':
            scanf("%d%d%d", &x, &y, &D);
            splayTree.ADD(x, y, D);
            break;
        case 'R':
            if('E' == buffer[3])
            {
                scanf("%d%d", &x, &y);
                splayTree.REVERSE(x, y);
            }
            else
            {
                scanf("%d%d%d", &x, &y, &T);
                splayTree.REVOLVE(x, y, T);
            }
            break;
        case 'I':
            scanf("%d%d", &x, &P);
            splayTree.INSERT(x, P);
            break;
        case 'D':
            scanf("%d", &x);
            splayTree.DELETE(x);
            break;
        case 'M':
            scanf("%d%d", &x, &y);
            splayTree.MIN(x, y);
            break;
        }
    }
    return 0;
}  

Splay tree的更多相关文章

  1. 纸上谈兵:伸展树(splay tree)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每次 ...

  2. bzoj 3223/tyvj 1729 文艺平衡树 splay tree

    原题链接:http://www.tyvj.cn/p/1729 这道题以前用c语言写的splay tree水过了.. 现在接触了c++重写一遍... 只涉及区间翻转,由于没有删除操作故不带垃圾回收,具体 ...

  3. 伸展树 Splay Tree

    Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...

  4. [转] Splay Tree(伸展树)

    好久没写过了,比赛的时候就调了一个小时,差点悲剧,重新复习一下,觉得这个写的很不错.转自:here Splay Tree(伸展树) 二叉查找树(Binary Search Tree)能够支持多种动态集 ...

  5. 树-伸展树(Splay Tree)

    伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...

  6. HDU-3436 Queue-jumpers 树状数组 | Splay tree删除,移动

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3436 树状数组做法<猛戳> Splay tree的经典题目,有删除和移动操作.首先要离散化 ...

  7. HDU1890 Robotic Sort Splay tree反转,删除

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890 题目中涉及数的反转和删除操作,需要用Splay tree来实现.首先对数列排序,得到每个数在数列 ...

  8. POJ-3468 A Simple Problem with Integers Splay Tree区间练习

    题目链接:http://poj.org/problem?id=3468 以前用线段树做过,现在用Splay Tree A了,向HH.kuangbin.cxlove大牛学习了各种Splay各种操作,,, ...

  9. Splay Tree的删除操作

    Splay Tree的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...

随机推荐

  1. CMD-CMD命令之新建一个用户!

    1>>>>>> 新建管理员账号: net user net user xxxxx 123 /add net localgroup administrators xx ...

  2. 问题-[WIN8.132位系统]安装Win8.1 遇到无法升级.NET Framework 3.5.1

    问题现象:安装Win8后都遇到了无法升级.NET Framework 3.5.1的问题,在线升级会遇到错误0x800F0906.这使得91手机助手等很多软件无法运行,更郁闷的是,网上几乎所有的解决办法 ...

  3. hdoj 4183 Pahom on Water

    Pahom on Water Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  4. hdoj 2803 The MAX【简单规律题】

    The MAX Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  5. AS3 IOC框架Spring Actionscript 的使用总结

    Spring Actionscript 是众多围绕依赖注入提供解决方案的Flex控制反转框架之一 AS3 下经典的IOC框架有Spring ActionScript.Parsley.Flicc和Swi ...

  6. [转载](iPhone开发)Bundle Display Name 改为中文。ap

    原文地址:(iPhone开发)Bundle Display Name 改为中文.app显示为中文作者:小新 要先在info的Localizations加入Chinese(zh-Hant) 再進到inf ...

  7. 【转】C++ 类中的static,const,及引用类型的初始化

    文档主要来自:http://blog.csdn.net/yjkwf/article/details/6067267 1. static类型 用static可以为类类型的所有对象所共有,像是全局对象,但 ...

  8. 跟我一起学extjs5(05--主界面上增加顶部和底部区域)

    跟我一起学extjs5(05--主界面上增加顶部和底部区域)         这一节为主界面加一个顶部区域和底部区域. 一个管理系统的界面能够粗分为顶部标题部分.中间数据展示和处理的部分.底部备注和状 ...

  9. POJ 3670 , 3671 LIS

    题意:两题意思差不多,都是给你一个序列,然后求最少需要改变多少个数字,使得成为一个最长不升,或者最长不降子序列. 当然3671是只能升序,所以更简单一点. 然后就没有什么了,用二分的方法求LIS即可. ...

  10. 深入理解JavaScript系列+ 深入理解javascript之执行上下文

    http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html http://blog.csdn.net/hi_kevin/article/d ...