HDU-4453

大佬讲的很清楚直接看大佬:

伸展树(Splay)_splay时间复杂度证明-CSDN博客

接下来是我的理解:

splay树 :为什么要使用 相比于AVL更快 没有那麽多复杂的平衡 相比于线段树 可以动态插入和删除

相比于普通二叉搜索树的不同在于splay()操作 可以将任意节点转移到根 (时间局部性,空间局部性) 可以进行一些动态插入删除 然后动态对区间进行反转 加数等操作 也是借鉴了一些线段树的原理

由于学splay数树的时候还没有学线段树 所以对延迟思想有一些困惑

后来查阅资料得知: 延迟思想就是推迟对区间的更新,将操作的标记存储在节点上,只有在需要访问或修改节点时才真正执行这些操作

下面是模板:

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

const int MAXN = 100010;

struct SplayTree {
    struct Node {
        int val, size, add, rev;
        int son[2];
        int parent;

        Node(int v = 0, int p = 0) : val(v), size(1), add(0), rev(0), parent(p) {
            son[0] = son[1] = 0;
        }
    };

    Node tree[MAXN];
    int root, cnt;

    SplayTree() : root(0), cnt(0) {}

    int NewNode(int parent, int val) {
        tree[++cnt] = Node(val, parent);
        return cnt;
    }

    void Update(int x) {
        tree[x].size = 1;
        if (tree[x].son[0]) tree[x].size += tree[tree[x].son[0]].size;
        if (tree[x].son[1]) tree[x].size += tree[tree[x].son[1]].size;
    }

    void PushDown(int x) {
        if (tree[x].rev) {
            swap(tree[x].son[0], tree[x].son[1]);
            if (tree[x].son[0]) tree[tree[x].son[0]].rev ^= 1;
            if (tree[x].son[1]) tree[tree[x].son[1]].rev ^= 1;
            tree[x].rev = 0;
        }
        if (tree[x].add) {
            if (tree[x].son[0]) {
                tree[tree[x].son[0]].add += tree[x].add;
                tree[tree[x].son[0]].val += tree[x].add;
            }
            if (tree[x].son[1]) {
                tree[tree[x].son[1]].add += tree[x].add;
                tree[tree[x].son[1]].val += tree[x].add;
            }
            tree[x].add = 0;
        }
    }

    void Rotate(int x) {
        PushDown(x);
        int y = tree[x].parent, z = tree[y].parent;
        int c = tree[y].son[0] == x ? 1 : 0;
        tree[y].son[!c] = tree[x].son[c];
        if (tree[x].son[c]) tree[tree[x].son[c]].parent = y;
        tree[x].parent = z;
        if (z) tree[z].son[tree[z].son[1] == y] = x;
        tree[x].son[c] = y;
        tree[y].parent = x;
        Update(y);
        Update(x);
    }

    void Splay(int x, int goal) {
        while (tree[x].parent != goal) {
            int y = tree[x].parent, z = tree[y].parent;
            if (z != goal) {
                if ((tree[z].son[0] == y) ^ (tree[y].son[0] == x)) Rotate(x);
                else Rotate(y);
            }
            Rotate(x);
        }
        if (!goal) root = x;
    }

    int FindK(int x, int k) {
        while (1) {
            PushDown(x);
            int sn = tree[x].son[0] ? tree[tree[x].son[0]].size + 1 : 1;
            if (sn == k) return x;
            if (sn > k) x = tree[x].son[0];
            else k -= sn, x = tree[x].son[1];
        }
    }

    void Insert(int pos, int val) {
        int x = FindK(root, pos), y = FindK(root, pos + 1);
        Splay(x, 0), Splay(y, x);
        tree[y].son[0] = NewNode(y, val);
        Update(y), Update(x);
    }

    int Delete(int pos) {
        int x = FindK(root, pos - 1), y = FindK(root, pos + 1);
        Splay(x, 0), Splay(y, x);
        int t = tree[tree[y].son[0]].val;
        tree[y].son[0] = 0;
        Update(y), Update(x);
        return t;
    }

    void Build(int l, int r, int &t, int fa, int arr[]) {
        if (l > r) return;
        int mid = (l + r) / 2;
        t = NewNode(fa, arr[mid]);
        Build(l, mid - 1, tree[t].son[0], t, arr);
        Build(mid + 1, r, tree[t].son[1], t, arr);
        Update(t);
    }

    void Init(int n, int arr[]) {
        cnt = root = 0;
        root = NewNode(0, -MAXN);
        tree[root].son[1] = NewNode(root, MAXN);
        Build(1, n, tree[tree[root].son[1]].son[0], tree[root].son[1], arr);
        Update(tree[root].son[1]);
        Update(root);
    }

    void Add(int l, int r, int val) {
        int x = FindK(root, l - 1), y = FindK(root, r + 1);
        Splay(x, 0), Splay(y, x);
        tree[tree[y].son[0]].add += val;
        tree[tree[y].son[0]].val += val;
        Update(y), Update(x);
    }

    void Reverse(int l, int r) {
        int x = FindK(root, l - 1), y = FindK(root, r + 1);
        Splay(x, 0), Splay(y, x);
        tree[tree[y].son[0]].rev ^= 1;
    }
};

int main() {
    SplayTree splay;
    int n, m, k1, k2;
    int arr[MAXN];

    while (scanf("%d%d%d%d", &n, &m, &k1, &k2) != EOF) {
        if (n == 0) break;
        for (int i = 1; i <= n; ++i) scanf("%d", &arr[i]);
        splay.Init(n, arr);

        while (m--) {
            char op[10];
            scanf("%s", op);
            if (op[0] == 'a') {
                int x;
                scanf("%d", &x);
                splay.Add(2, k2 + 1, x);
            } else if (op[0] == 'r') {
                splay.Reverse(2, k1 + 1);
            } else if (op[0] == 'i') {
                int x;
                scanf("%d", &x);
                splay.Insert(2, x);
            } else if (op[0] == 'd') {
                splay.Delete(2);
            } else if (op[0] == 'm') {
                int x;
                scanf("%d", &x);
                if (x == 1) {
                    int y = splay.Delete(splay.cnt);
                    splay.Insert(1, y);
                } else {
                    int y = splay.Delete(2);
                    splay.Insert(splay.cnt + 1, y);
                }
            } else if (op[0] == 'q') {
                printf("%d\n", splay.tree[splay.FindK(splay.root, 2)].val);
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值