类别:二叉排序树

空间效率: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. Storm与Hadoop的角色和组件比较

    Storm与Hadoop的角色和组件比较 Storm 集群和 Hadoop 集群表面上看很类似.但是 Hadoop 上运行的是 MapReduce 作业,而在 Storm 上运行的是拓扑 Topolo ...

  2. PC-信使服务之不用聊天软件也能通信

    net send 192.168.1.2 OK 二台电脑都要开启messenger服务.

  3. javascript function对象

    <html> <body> <script type="text/javascript"> Function.prototype.get_my_ ...

  4. T-SQL语句查看作业等信息

    因服务器需要迁移,需要将现有JOB迁移至新服务器,待服务器调整完毕,则重新迁移到原服务器,所以在做迁移之前希望将现有JOB进行备份,不至于乱了执行时间.1.查看所有作业列表USE master SEL ...

  5. testlink邮件设置(centos 7)

    上一篇文章在centos 7上安装了testlink(CentOS 7下安装xampp和testlink),本篇进行邮件设置,可在进行testlink密码修改.用例指派时进行邮件通知 1.修改conf ...

  6. Join-Path(拼接路径)

    $a="d:" $a="d:\ab" $b="abcd" $c="m.txt" @($a,$b,$c) -join '\ ...

  7. oncopy和onpaste

    在Javascript中,有对应的事件能够监听复制和粘贴,那就是oncopy和onpaste. oncopy: demo: <body oncopy="alert('不能复制');re ...

  8. 【Unity Shaders】使用CgInclude让你的Shader模块化——创建CgInclude文件存储光照模型

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...

  9. ListView视图缓存错位问题

    由于之前写Scroller应用:ListView滑动删除遇到Item视图错位问题,观察发现第1item位置改变后,第1+10的item布局也跟着改变.假设使用ScrollView+ListView,把 ...

  10. [Javascript] Lodash: Refactoring Simple For Loops (_.find, _.findLast, _.filter)

    This lesson shows how to refactor your old loops into using a simpler and more powerful lodash-style ...