【BZOJ1503】Splay 区间删除 (1)

来源:互联网 发布:手机淘宝无法识别图片 编辑:程序博客网 时间:2024/05/20 23:56
#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