【BZOJ1503】Splay 区间删除 (1)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <iostream>
using namespace std;

//const int MAXN = 1e5 + 5;

int n, minn;
int cnt;

struct Splay {
    struct Node {
        Node *fa, *ch[2], **root;
        int size, cnt, x;

        Node(Node **root, Node *fa, int x) : root(root), fa(fa), x(x), size(1), cnt(1)
        {
            ch[0] = ch[1] = NULL;
        }

        int relation()
        {
            return this == fa->ch[1] ? 1 : 0;
        }

        void maintain()
        {
            size = cnt;
            if (ch[1]) size += ch[1]->size;
            if (ch[0]) size += ch[0]->size;
        }

        void rotate()
        {
            Node *old = fa;
            int r = relation();

            fa = old->fa;
            if (old->fa)
            {
                old->fa->ch[old->relation()] = this;
            }

            if (ch[r ^ 1])
            {
                ch[r ^ 1]->fa = old;
            }
            old->ch[r] = ch[r ^ 1];

            old->fa = this;
            ch[r ^ 1] = old;

            old->maintain();
            maintain();

            if (!fa)
            {
                *root = this;
            }
        }

        void splay(Node *target = NULL)
        {
            while (fa != target)
            {
                if (fa->fa == target)
                {
                    rotate();
                }
                else if (relation() == fa->relation())
                {
                    fa->rotate();
                    rotate();
                }
                else
                {
                    rotate();
                    rotate();
                }
            }
        }

        Node *pred()
        {
            //求前驱和后继之前必须是根
            this->splay();
            Node *v = ch[0];
            while (v->ch[1]) v = v->ch[1];
            return v;
        }

        Node *succ()
        {
            this->splay();
            Node *v = ch[1];
            while (v->ch[0]) v = v->ch[0];
            return v;
        }

        int rank()
        {
            return ch[0] ? ch[0]->size : 0;
        }
    } *root;

    Splay() : root(NULL)
    {
        insert(INT_MAX);
        insert(INT_MIN);
    }

    Node *insert(int x)
    {
        Node **v = &root, *fa = NULL;

        while ((*v) != NULL && (*v)->x != x)
        {
            fa = *v;
            fa->size++;

            if (x < fa->x)
            {
                v = &fa->ch[0];
            }
            else
            {
                v = &fa->ch[1];
            }
        }

        if ((*v) != NULL)
        {
            (*v)->cnt++;
            (*v)->size++;
        }
        else
        {
            (*v) = new Node(&root, fa, x);
        }

        (*v)->splay();

        return root;
    }

    Node *find(int x)
    {
        Node *v = root;

        while (v != NULL && v->x != x)
        {
            if (x < v->x)
            {
                v = v->ch[0];
            }
            else
            {
                v = v->ch[1];
            }
        }

        if (v) v->splay();
        return v;
    }

    // void erase(Node *v)
    // {
    //     Node *pred = v->pred(), *succ = v->succ();
    //     pred->splay();
    //     succ->splay(pred);
    //
    //     if (v->cnt > 1)
    //     {
    //         v->size--;
    //         v->cnt--;
    //     }
    //     else
    //     {
    //         delete succ->ch[0];
    //         succ->ch[0] = NULL;
    //     }
    //
    //     succ->size--;
    //     pred->size--;
    // }
    //
    // void erase(int x)
    // {
    //     Node *v = find(x);
    //
    //     if (!v) return;
    //     erase(v);
    // }

    // int rank(int x)
    // {
    //     Node *v = find(x);
    //
    //     if (v == NULL)
    //     {
    //         v = insert(x);
    //         int res = v->rank();
    //         erase(v);
    //         return res;
    //     }
    //     else
    //     {
    //         return v->rank();
    //     }
    // }

    int kth(int k)
    {
        Node *v = root;

        while (!(k >= v->rank() && k < v->rank() + v->cnt))
        {
            if (k < v->rank())
            {
                v = v->ch[0];
            }
            else
            {
                k -= v->rank() + v->cnt;
                v = v->ch[1];
            }
        }
        v->splay();
        return v->x;
    }

    // void add(int k, Node *v)
    // {
    //     v->x += k;
    //     if (v->ch[0]) add(k, v->ch[0]);
    //     if (v->ch[1]) add(k, v->ch[1]);
    // }

    void erase(Node *l, Node *r)//删除区间
    {
        Node *pred = l->pred(), *succ = r->succ();

        pred->splay();
        succ->splay(pred);

        delete succ->ch[0];
        succ->ch[0] = NULL;

        succ->maintain();
        pred->maintain();
    }

    void kill(int l, int r)
    {
        Node *vl = find(l), *vr = find(r);
        if (!vl) vl = insert(l);
        if (!vr) vr = insert(r);
        erase(vl, vr);

        // while (v->ch[1]->x < minn)
        // {
        //     v = v->ch[1];
        // }
        //
        // v->splay();
        // cnt += v->rank();
        // v = v->ch[0];
        //
        // while (v->ch[0] || v->ch[1])
        // {
        //     if (v->ch[0]) erase(v->ch[0]);
        //     if (v->ch[1]) erase(v->ch[1]);
        // }
        //
        // // if (v->x < minn)
        // // {
        // //     if (v->)
        // //     erase(v);
        // // }
        // //
    }

    int size()
    {
        return root->size - 2;
    }
} splay;

int main()
{
    int add = 0;
    scanf("%d %d", &n, &minn);

    for (int i = 0; i < n; i++)
    {
        //char fu;
        int k;
        //cin >> fu >> k;
        //scanf("%c %d", &fu, &k);
        // scanf("%c", &fu);
        // scanf("%d", &k);
        //这里为什么不能用scanf?

        char s[2];
        scanf("%s %d", s, &k);

        if (s[0] == 'I')
        {
            // if (k < minn)
            // {
            //     cnt++;
            // }
            if (k >= minn)
            {
                k -= add;
                splay.insert(k);
            }
            // splay.insert(k);
            // if (splay.find(k)->x < minn)
            // {
            //     splay.erase(k);
            // }
        }

        else if (s[0] == 'A')
        {
            add += k;
            //splay.add(k, splay.root);
        }

        else if (s[0] == 'S')
        {
            add -= k;
            //splay.add(-k, splay.root);
            //splay.kill(splay.root);

            int L = minn;
            L -= add;
            //int oldSize = splay.root->size - 2;
            int oldSize = splay.size();

            splay.kill(INT_MIN + 1, L - 1);
            cnt += oldSize - splay.size();
        }

        else if (s[0] == 'F')
        {
            if (k > splay.root->size - 2 || k < 1)
            {
                printf("-1\n");
            }
            else
            {
                printf("%d\n", splay.kth((splay.root->size - 2) - k + 1) + add);
            }
        }
    }

    printf("%d\n", cnt);

    return 0;
}

抄了sulfur6【团长的博客!】和Menci两位神犇的代码【也就是说基本上没有我自己写的,我把代码放这主要是想写一些错误啥的!】。感谢!

这道题调的我已经变身郁闷的程序员了好吗qnq
那一条条来说一下我的心(zhi)路(zhang)历程

1)Splay里的while老写成if
2)区间删除我写的奇奇怪怪【就是不会写然后xjb写】最后区间删除的做法和删一个点思想一样,不同的就是是把那个区间而不是一个点转过去【好像有一种把一个区间缩成点的意思?】然后传进去的参数是两个数字,这样很方便。
3)我加工资和减工资一开始都是写的递归下去全改了,然后就是段错误。【我改成打标记就没有段错误了,可能是我递归也写错了吧】【我每次调Splay都会在求前驱和后继那里段错误!每次都会!话说求前驱和后继需要转到根?这个程序里可能在什么我不知道的地方转过去了吧(挠头)我再好好看看(唉还是有不懂的地方啊qnq一知半解的。。。。。)】这是在全局打标记,团长说Menci的是在Splay里打标记 ,我去学!
4)然后减工资踢人的时候就要加上标记的相反数。我一开始想工资下限又没有变,为什么要改?这样想,他们的工资全涨了一个数,但实际上只是标记了一下,没有给他们实际改工资,那这样的话工资下限以下的人要被踢掉【哦不,是辞职】但是按原先的工资下限的话肯定不行,因为这样涨工资之后实际上在工资下限以上的人也会被踢【就这样说吧owo】那就让工资下限降低,他们应该涨多少就工资下限就降多少【就相当于相对运动?你往东走就相当于我往西走这样】BINGO!问题解决!,时间从每次O(n)变成了O(1)【好像是这样,时间复杂度我还不是很会算qnq(托腮)】还有查询的时候要加上标记。
5)改成了和团长的代码差不多一样之后还是过不了样例。把scanf改成cin之后好了很多!(还是过不了。。。)这里我不懂,问了Menci。说是因为scanf(“%c”)会把’\n’和’\0’也读进去(大坑啊)【话说还有两个大坑,知乎回答里说的,if (x = 0) die Gavin;(hhhhhh顺手黑栋栋(别打我,逃))和int a, b; long long c = a * b;(然而还是逃脱不了爆int的命运(逃))】Fancy学姐的解决方法是每次读一个字符串(超强!)。开一个char s[2] 用的时候取s[0]就行【这里是char s[数组内的元素个数],我还以为开char s[1],然后s[0]存字符,s[1]存’\0’就行呢qnq然而事实根本不是我想象的那样(摊手)我果真naive】
6)可是被踢出去的人数还是统计错了,我把求树的大小从每次求改成写在Splay的函数里不知道为什么就对了,我觉得并没有什么区别啊【回来仔细研究系列。。。。】

唉,可是不易= =我一个抄板子都抄不对的废人。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值