【数据结构】Splay伸展树

Alex_Shen
2020-12-10 / 0 评论 / 0 点赞 / 62 阅读 / 7,228 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-04-06,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

问题 A: Splay —— Ver.I

题目描述

在这里插入图片描述

输入

第一行包含一个整数n,表示初始序列的长度。 以下n行每行包含一个整数,描述初始的序列。 接下来一行包含一个整数n,表示插入操作的数目。 以下m行每行描述一个操作。
接下来一行包含一个整数q,表示查询和删除操作的总数目,以下q行描述一个操作

输出

对于所有操作,输出正确的答案。

样例输入

5
1 2 3 4 5
3
ADD 9
ADD 10
ADD 199
5
QUERY 1
QUERY 3
DELETE 1
DELETE 3
QUERY 3

样例输出

the number is good
the number is good
2 3 4 5 9 10 199
2 4 5 9 10 199
the number is bad

题解
参考网址

#include <iomanip>
#include <iostream>
using namespace std;

template <class T>
class SplayTreeNode {
public:
    T key;
    SplayTreeNode* left;
    SplayTreeNode* right;


    SplayTreeNode() :left(NULL), right(NULL) {}

    SplayTreeNode(T value, SplayTreeNode* l, SplayTreeNode* r) :
        key(value), left(l), right(r) {}
};

template <class T>
class SplayTree {
private:
    SplayTreeNode<T>* mRoot;

public:
    SplayTree();
    void inOrder();
    SplayTreeNode<T>* search(T key);
    void splay(T key);
    void insert(T key);
    void remove(T key);
private:
    void inOrder(SplayTreeNode<T>* tree) const;
    SplayTreeNode<T>* search(SplayTreeNode<T>* x, T key) const;
    SplayTreeNode<T>* splay(SplayTreeNode<T>* tree, T key);
    SplayTreeNode<T>* insert(SplayTreeNode<T>*& tree, SplayTreeNode<T>* z);
    SplayTreeNode<T>* remove(SplayTreeNode<T>*& tree, T key);
};

template <class T>
SplayTree<T>::SplayTree() :mRoot(NULL)
{
}


template <class T>
void SplayTree<T>::inOrder(SplayTreeNode<T>* tree) const
{
    if (!tree)return;
    if (tree->left) {
        inOrder(tree->left);
    }
    cout << tree->key << " ";
    if (tree->right) {
        inOrder(tree->right);
    }
}

template <class T>
void SplayTree<T>::inOrder()
{
    inOrder(mRoot);
}

template <class T>
SplayTreeNode<T>* SplayTree<T>::search(SplayTreeNode<T>* x, T key) const
{
    if (x == NULL || x->key == key)
        return x;

    if (key < x->key)
        return search(x->left, key);
    else
        return search(x->right, key);
}

template <class T>
SplayTreeNode<T>* SplayTree<T>::search(T key)
{
    return search(mRoot, key);
}

template <class T>
SplayTreeNode<T>* SplayTree<T>::splay(SplayTreeNode<T>* tree, T key)
{
    SplayTreeNode<T> N, * l, * r, * c;

    if (tree == NULL)
        return tree;

    N.left = N.right = NULL;
    l = r = &N;

    for (;;)
    {
        if (key < tree->key)
        {
            if (tree->left == NULL)
                break;
            if (key < tree->left->key)
            {
                c = tree->left;                       
                tree->left = c->right;
                c->right = tree;
                tree = c;
                if (tree->left == NULL)
                    break;
            }
            r->left = tree;                
            r = tree;
            tree = tree->left;
        }
        else if (key > tree->key)
        {
            if (tree->right == NULL)
                break;
            if (key > tree->right->key)
            {
                c = tree->right;                     
                tree->right = c->left;
                c->left = tree;
                tree = c;
                if (tree->right == NULL)
                    break;
            }
            l->right = tree;                     
            l = tree;
            tree = tree->right;
        }
        else
        {
            break;
        }
    }

    l->right = tree->left;
    r->left = tree->right;
    tree->left = N.right;
    tree->right = N.left;

    return tree;
}

template <class T>
void SplayTree<T>::splay(T key)
{
    mRoot = splay(mRoot, key);
}

template <class T>
SplayTreeNode<T>* SplayTree<T>::insert(SplayTreeNode<T>*& tree, SplayTreeNode<T>* z)
{
    SplayTreeNode<T>* y = NULL;
    SplayTreeNode<T>* x = tree;

    while (x != NULL)
    {
        y = x;
        if (z->key < x->key)
            x = x->left;
        else if (z->key > x->key)
            x = x->right;
        else
        {
            delete z;
            return tree;
        }
    }

    if (y == NULL)
        tree = z;
    else if (z->key < y->key)
        y->left = z;
    else
        y->right = z;

    return tree;
}

template <class T>
void SplayTree<T>::insert(T key)
{
    SplayTreeNode<T>* z = NULL;

    if ((z = new SplayTreeNode<T>(key, NULL, NULL)) == NULL)
        return;

    mRoot = insert(mRoot, z);
    mRoot = splay(mRoot, key);
}

template <class T>
SplayTreeNode<T>* SplayTree<T>::remove(SplayTreeNode<T>*& tree, T key)
{
    SplayTreeNode<T>* x;

    if (tree == NULL)
        return NULL;

    if (search(tree, key) == NULL)
        return tree;

    tree = splay(tree, key);

    if (tree->left != NULL)
    {
        x = splay(tree->left, key);
        x->right = tree->right;
    }
    else
        x = tree->right;

    delete tree;

    return x;

}

template <class T>
void SplayTree<T>::remove(T key)
{
    mRoot = remove(mRoot, key);
}

int main()
{
    SplayTree<int>* tree = new SplayTree<int>();
    int n;
    cin >> n;
    while (n--) {
        int num;
        cin >> num;
        tree->insert(num);
    }
    cin >> n;
    while (n--) {
        int num;
        string str;
        cin >> str >> num;
        if (str == "ADD")
            tree->insert(num);
    }
    cin >> n;
    while (n--) {
        int num;
        string str;
        cin >> str >> num;
        if (str == "QUERY") {
            if (NULL != tree->search(num))
                cout <<  "the number is good" << endl;
            else
                cout << "the number is bad" << endl;
        }
        else if (str == "DELETE") {
            if (NULL != tree->search(num)) {
                tree->remove(num);
                tree->inOrder();
                cout << endl;
            }
            else
                cout << "Failed" << endl;
        }
    }
    return 0;
}


问题 B: 宠物收养所(Splay —— 前驱后继操作)

题目描述

最近,贝贝开了一间宠物收养所。收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。每个领养者都希望领养到自己满意的宠物,贝贝根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养所的宠物一个特点值。
这样他就能够很方便的处理整个领养宠物的过程了,宠物收养所总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少。
1. 被遗弃的宠物过多时,假若到来一个领养者,这个领养者希望领养的宠物的特点值为a,那么它将会领养一只目前未被领养的宠物中特点值最接近a的一只宠物。(任何两只宠物的特点值都不可能是相同的,任何两个领养者的希望领养宠物的特点值也不可能是一样的)如果有两只满足要求的宠物,即存在两只宠物他们的特点值分别为a-b和a+b,那么领养者将会领养特点值为a-b的那只宠物。
2. 收养宠物的人过多,假若到来一只被收养的宠物,那么哪个领养者能够领养它呢?能够领养它的领养者,是那个希望被领养宠物的特点值最接近该宠物特点值的领养者,如果该宠物的特点值为a,存在两个领养者他们希望领养宠物的特点值分别为a-b和a+b,那么特点值为a-b的那个领养者将成功领养该宠物。 一个领养者领养了一个特点值为a的宠物,而它本身希望领养的宠物的特点值为b,那么这个领养者的不满意程度为abs(a-b)。
【任务描述】你得到了一年当中,领养者和被收养宠物到来收养所的情况,希望你计算所有收养了宠物的领养者的不满意程度的总和。这一年初始时,收养所里面既没有宠物,也没有领养者。
(abs(3-2) + abs(2-4)=3,最后一个领养者没有宠物可以领养)

输入

第一行为一个正整数n,n<=80000,表示一年当中来到收养所的宠物和领养者的总数。接下来的n行,按到来时间的先后顺序描述了一年当中来到收养所的宠物和领养者的情况。每行有两个正整数a, b,其中a=0表示宠物,a=1表示领养者,b表示宠物的特点值或是领养者希望领养宠物的特点值。(同一时间呆在收养所中的,要么全是宠物,要么全是领养者,这些宠物和领养者的个数不会超过10000个)

输出

仅有一个正整数,表示一年当中所有收养了宠物的领养者的不满意程度的总和mod 1000000以后的结果。

样例输入

5
0 2
0 4
1 3
1 2
1 5

样例输出

3

题解

#include <iostream>
using namespace std;
#define maxn 100005  
#define INF 1 << 31

int pre[maxn], ch[maxn][2], key[maxn], rt, tot;

void Node(int& r, int fa, int val) {
    r = ++tot;
    pre[r] = fa;
    key[r] = val;
    ch[r][0] = ch[r][1] = 0;
}

void rotate(int r, int kind) {
    int y = pre[r];
    ch[y][!kind] = ch[r][kind];
    pre[ch[r][kind]] = y;
    if (pre[y]) {
        ch[pre[y]][ch[pre[y]][1] == y] = r;
    }
    ch[r][kind] = y;
    pre[r] = pre[y];
    pre[y] = r;
}

void splay(int r, int goal) {
    while (pre[r] != goal) {
        if (pre[pre[r]] == goal) {
            rotate(r, ch[pre[r]][0] == r);
        }
        else {
            int y = pre[r];
            int kind = ch[pre[y]][0] == y;
            if (ch[pre[r]][!kind] == r) {
                rotate(y, kind);
                rotate(r, kind);
            }
            else {
                rotate(r, !kind);
                rotate(r, kind);
            }
        }
    }
    if (goal == 0) rt = r;
}

int insert(int val) {
    int r = rt;
    while (1) {
        if (val < key[r]) {
            if (ch[r][0]) r = ch[r][0];
            else break;
        }
        else if (val > key[r]) {
            if (ch[r][1]) r = ch[r][1];
            else break;
        }
        else {
            splay(r, 0);
            return 0;
        }
    }
    Node(ch[r][val > key[r]], r, val);
    splay(ch[r][val > key[r]], 0);
    return 1;
}

int getmin(int val) {
    int r = rt;
    if (ch[r][0] == 0)
        return 0;
    r = ch[r][0];
    while (ch[r][1])
        r = ch[r][1];
    return key[r];
}

int getmax(int val) {
    int r = rt;
    r = ch[r][1];
    if (r == 0) 
        return INF;
    while (ch[r][0])
        r = ch[r][0];
    return key[r];
}

void findnode(int x) {
    int r = rt;
    while (key[r] != x) {
        if (x < key[r]) r = ch[r][0];
        else r = ch[r][1];
    }
    splay(r, 0);
}

void remove() {
    if (!rt)
        return;
    int y;
    if (ch[rt][1] == 0) {
        rt = ch[rt][0];
    }
    else {
        y = ch[rt][1];
        while (ch[y][0]) {
            y = ch[y][0];
        }
        splay(y, rt);
        ch[y][0] = ch[rt][0];
        pre[ch[rt][0]] = y;
        rt = y;
    }
    pre[rt] = 0;
}

int main() {
    int n, x, op, cur, cnt;
    cin >> n;
    long long ans = 0;
    rt = tot = 0;
    for (int i = 1; i <= n; ++i) {
        ans %= 1000000;
        cin >> op >> x;
        if (rt == 0) {
            Node(rt, 0, x);
            cur = op;
            cnt = 1;
        }
        else {
            if (cnt == 0) {
                cnt += insert(x);
                cur = op;
            }
            else if (op == cur) {
                cnt += insert(x);
            }
            else if (insert(x) == 0) {
                cnt--;
                remove();
                continue;
            }
            else {
                int l = getmin(x);
                int r = getmax(x);
                remove();
                if (l == 0) {
                    ans += r - x;
                    remove();
                }
                else if (r == INF) {
                    ans += x - l;
                    findnode(l);
                    remove();
                }
                else {
                    if (x - l > r - x) {
                        ans += r - x;
                        findnode(r);
                        remove();
                    }
                    else {
                        ans += x - l;
                        findnode(l);
                        remove();
                    }
                }
                cnt--;
            }
        }
    }
    cout << ans % 1000000 << endl;
}

0

评论区