• 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;
    }
  • 相关阅读:
    Qt支持中文显示
    C/C++ 知识点---LIB和DLL的区别与使用(网摘)
    Inno Setup
    C/C++ 知识点---字符串函数
    es5 JSON对象
    Es567严格模式
    mysql常用命令
    promise 获取文件内容
    postman连接不了localhost问题解决
    node---处理post请求
  • 原文地址:https://www.cnblogs.com/Lyush/p/2551996.html
Copyright © 2020-2023  润新知