伸展树学习小结

来源:互联网 发布:现金贷系统源码 编辑:程序博客网 时间:2024/06/02 16:22

        第一次碰到伸展树的题目是在天津网赛上, 比赛的时候用双向链表A掉了, 第一次碰到, 也没想去看看的。 后来又有人问我会不会伸展树, 这~, 果断要去看了= 0 =。

       先去百度了一下, 伸展树是二叉排序树, 所有的操作都基于旋转操作, 旋转后可以使树变得平衡, 使得查找的的复杂度在log(n), 好像很DBL的样子。 随后去网上找了一份PDF开始学习。

        PDF(http://wenku.baidu.com/view/b9cc2c75a417866fb84a8ee4.html)上详细说明了如何旋转, 不过刚接触, 看的还是有点晕, 自己照着写了一个, 写的比较冗长。 然后去HH大神的博客(http://www.notonlysuccess.com/index.php/splay-tree/)看了下他写的splay tree, 果断借鉴过来= 0 =。 接下来就是实战环节了, 去开了个DIY, 第一题选择了HDU 3487 Play with Chain。 刚开始接触, 对其中的旋转操作也还不是很熟悉, 敲好代码以后各种BUG, DEBUG的时候, 旋转一下就画个图, 看看对不对, 调了好久, 总算是过来样例, 提交1Y大笑。 接下来的题做得就轻松些了, 做了几道题后感觉伸展树处理区间都比较套路。

        建图比较随意, 只要保证是排序树就可以, 怎么建都没什么关系。 处理一段区间的话, 就通过选择把这段区间转到根节点的右孩子的下面, 然后再进一步处理, 插入、 删除操作也很像, 基本上都是通过旋转在根节点的有孩子那里做文章。为了处理起来方便, 通常还会给splay tree人为加两个端点结点, 这样很多边界情况就不用讨论了。 其他部分就和线段树比较像, 一样处理就好。

        splay tree主要的函数就3个, 其他的函数可以根据具体的问题具体处理。 下面贴出模板(主要来自HH大牛)。

        (初学, 望大牛指点)

#define KT ch[ch[root][1]][0]int root, ch[N][2], fa[N], sz[N];void rotate(int x, bool f) //选择操作, 左旋还是右旋看f{int y = fa[x];int z = fa[y];pushdown(y);pushdown(x);ch[y][!f] = ch[x][f];fa[ch[x][f]] = y;fa[x] = z;if(z)ch[z][ch[z][1] == y] = x;ch[x][f] = y;fa[y] = x;pushup(y);}void splay(int x, int g) //把结点x旋转到g{int y = fa[x];pushdown(x);while(y != g){int z = fa[y];bool f = (ch[y][0] == x);if(z != g && f == (ch[z][0] == y))rotate(y, f);rotate(x, f);y = fa[x];}pushup(x);if(g == 0)root = x;}void rotateto(int k, int g) //把第k个结点旋转到g{int x = root;pushdown(x);while(sz[ch[x][0]] != k){if(k < sz[ch[x][0]])x = ch[x][0];else{k -= sz[ch[x][0]] + 1;x = ch[x][1];}pushdown(x);}splay(x, g);}



原创粉丝点击