zoukankan      html  css  js  c++  java
  • POJ3468 A Simple Problem with Integers Splay树

    该题是一道简单的区间求和题,跟杭电的敌兵布阵很是想象,这里是使用Splay写的。

    Splay就是伸展的意思,因为该树在使用过程中会大量的执行Rotate函数,该函数就是在保持二叉树中序遍历不变的情况下,使树的结构发生变化。

    该题中,二叉树中存储的值并不一定要求是顺序的,满足左孩子比根节点小,右孩子比根节点大,其大小只是一个构树时的顺序关系。每次旋转能够时确保目标节点一定要在旋转节点的下方,因为任何Rotate操作旋转节点的深度都是在降低的。Splay数的作用在于能够Splay操作选出区间,首先建立两个理论上的无穷小和无穷大点,如果选择区间[a, b],那么将
    a-1号节点旋转到根节点,再将b+1号节点旋转到根节点之下,由于b+1 > a-1 恒成立,所以b+1号节点一定是其右孩子,根据中序遍历的关系,a-1之后就是b+1的左子树,再就是b+1了,因此我们就选择出了区间[a, b]。再在上面做一些操作即可。

    代码如下:

    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #define L(x) tree[x].ch[0]
    #define R(x) tree[x].ch[1]
    #define Key L(R(rt))
    #define MAXN 100005
    using namespace std;
    
    int N, Q, queue[MAXN], seq[MAXN], rt, front;
    
    struct Node
    {
        int di, v, ch[2], lazy, fa;
        long long s;
        void New(int x, int y) {
            di = 1, v = s = x, fa = y;
            lazy = ch[0] = ch[1] = 0;
        }
        void Add(int x) {
            lazy += x;
            s += (long long)di * x;
            v += x;
        }
    }tree[MAXN];
    
    void push_up(int x)
    {
        tree[x].di = 1+tree[L(x)].di+tree[R(x)].di;
        tree[x].s = tree[x].v+tree[L(x)].s+tree[R(x)].s;
    }
    
    void push_down(int x)
    {
        if (tree[x].lazy) {
            tree[L(x)].Add(tree[x].lazy);
            tree[R(x)].Add(tree[x].lazy);
            tree[x].lazy = 0;
        }
    }
    
    void rotate(int x, int f)
    {
        int y = tree[x].fa, z = tree[y].fa;
        push_down(y), push_down(x);
        tree[y].ch[!f] = tree[x].ch[f];
        tree[ tree[y].ch[!f] ].fa = y;
        tree[x].ch[f] = y;
        tree[y].fa = x;
        tree[x].fa = z;
        if (z) {
            tree[z].ch[R(z) == y] = x;
        }  
        push_up(y);
    }
    
    void splay(int x, int obj)
    {
        int y, z;
        while (tree[x].fa != obj) {
            y = tree[x].fa, z = tree[y].fa;
            if (z == obj) {
                rotate(x, L(y) == x);
            }
            else {
                if (x == L(y) && y == L(z)) {
                    rotate(y, 1), rotate(x, 1);
                }
                else if (x == R(y) && y == R(z)) {
                    rotate(y, 0), rotate(x, 0);
                }
                else if (x == R(y) && y == L(z)) {
                    rotate(x, 0), rotate(x, 1);
                }
                else {
                    rotate(x, 1), rotate(x, 0);
                }
            }
        }
        push_up(x);
    }
    
    void select(int x, int k, int obj)
    {
        if (k != tree[L(x)].di) {
            if (k < tree[L(x)].di) {
                select(L(x), k, obj);
            }
            else {
                select(R(x), k-tree[L(x)].di-1, obj);
            }
        }
        else {
            splay(x, obj);
            if (obj == 0) {
                rt = x;
            }
        }
    }
    
    void build(int &x, int l, int r, int fa)
    {
        if (l > r)  return;
        int m = (l+r) >> 1;
        x = queue[++front];
        tree[x].New(seq[m], fa);
        build(L(x), l, m-1, x);
        build(R(x), m+1, r, x);
        push_up(x);
    }
    
    void init()
    {
        for (int i = 0; i < MAXN; ++i) {
            queue[i] = i;
        }
        rt = queue[++front];
        tree[rt].New(0, 0);
        R(rt) = queue[++front];
        tree[R(rt)].New(0, rt);
        build(Key, 1, N, R(rt));  // 构造出两个边界点以及题给的信息区间
    //    push_up(R(rt));
    //    push_up(rt);
    }
    
    void travel(int x)
    {
        if (x) {
            travel(L(x));
            printf("di=%d, s=%lld, v=%d, fa.v=%d\n", tree[x].di, tree[x].s, tree[x].v, tree[tree[x].fa].v);
            travel(R(x));
        }
    }
    
    int main()
    {
        char op[5];
        int x, y, z;
        while (scanf("%d %d", &N, &Q) == 2) {
            for (int i = 1; i <= N; ++i) {
                scanf("%d", &seq[i]);
            }
            init();
            while (Q--) {
                scanf("%s %d %d", op, &x, &y);
                select(rt, x-1, 0);
                select(rt, y+1, rt);
                if (op[0] == 'C') {
                    scanf("%d", &z);
                    tree[Key].Add(z);
                }
                else {
                    printf("%lld\n", tree[Key].s);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    Infopath Notify 弹出提示信息
    window.showModalDialog 返回值
    【转】获得正文内容中的所有img标签的图片路径
    Json Datable Convert
    Sharepoint 列表 附件 小功能
    Surgey 权限更改
    SQL 触发器用于IP记录转换
    Caml语句 查询分配给当前用户及当前组
    jquery 1.3.2 auto referenced when new web application in VSTS2010(DEV10)
    TFS diff/merge configuration
  • 原文地址:https://www.cnblogs.com/Lyush/p/2551996.html
Copyright © 2011-2022 走看看