2013 多校第九场 hdu 4699 Editor(vector OR splay tree)

来源:互联网 发布:智能网络液晶电视 编辑:程序博客网 时间:2024/06/16 00:17

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4699

题目大意:一个文件编译器,有一个指针,五种操作:(1)在指针前面插入一个数(2)把指针前的数删除(3)指针往左移一位(4)指针往右移一位(5)询问前k个数的最大前缀和(其中 k <= n),n 为指针位置,并输出。

思路:以指针为分界线,分别建两个栈,前面为 a,后面为b,由于k<=n,那么对于a 再维护两个值s和s_max,由于b中的元素会加到 a 的栈顶,那么还要在 b 中记录一个 val 值。由于要询问 k ,那么用vector模拟就行了。

I x a.push(x)

D a.pop()

L a.push(b.pop())

R b.push(a.pop())

Q k a[k].s_max

概括起来就是上面这几句。比赛的时候,想太多,我们当时想到链表,天真的以为插入、删除一个数,还要去更新后面的 s和s_max,其实不用,因为 k<=n,只要跟着指针的移动走就好了。。 SB 了,挫啊。。

赛后又问了下别人,他们说他们是用伸展树做的,哎,表示没学过伸展树,后来一看,由于操作简单,这样简单维护下就可以了。。无语。。

没办法,不会就要学,昨天看了一天伸展树,今天过来敲这道题目,调试老半天,调完过样例,来了一发,TLE了。。 由于我之前的L、R都是直接将数旋转的,让树根为指针所在位置,Q的时候,一遍找下去,可能这样比较耗时,后来,拿了 pos 来记录位置,询问时直接旋转k大的数,然后输出,过了样例,一交,发现是 WA,找了老半天错误,然后TLE了。。终于在各种小地方的优化下,以 1968ms 的微弱优势成功AC,虽然时间有点那个啥,但还是兴奋啊,毕竟写了两天了啊,从WA到TLE再到AC。。T^T

总结一下自己犯的各种SB错误:(1)第一遍写,我的 s 表示的是所有前面的和(不是以它为跟的子树),然后又搞了个延时标记,插入删除时对右儿子放一个,然后 s_max 表示的是左边的 s 最大值,上传时只上传 size 。先不说这个s,这个 s_max 就有问题,当前节点的 s_max 是不能由它的左子树过来的(在我这种SB定义下),会小,因为它左儿子可能还有右儿子,也就是说它和它的左儿子不是挨着的。貌似延时标记这样处理这个 s 是对的(当然也只是我个人想想,还缺乏验证)。。(2)感觉到这个 s 有问题,因为我感觉一个节点的每个值,都是相对于以它为根节点的子树来说的,然后我就删掉了这个延时标记,因为这样插入、删除旋转后只影响到树根的维护的值的变化,然后在 push_up(maintain)这里加了 s 和 s_max,然后由于是定义全都换成以它为根的子树了,那么 s_max 也变了,但是第一遍写的时候,还是有一个地方写错了,我写的是 max( ch[ 0 ]->s_max , ch[ 0 ]->s +v ,ch[ 1 ]->s_max ),这里就是一直没发现,今天吃完午饭,然后造随机数据才发现的。。 = = ,ch[ 1 ]->s_max 应该改为 ch[ 1 ]->s_max + v + ch[ 0 ]->s,因为是前缀和,明显要把左子树的和给拿过来嘛,SB了。。 这样改了之后,又交,发现TLE,就感觉别人写的 splay 能过,我的应该也差不多,我把上面求 max 那个分 if 讨论(其实我换 null 的原因就是省的 if 讨论。。囧),这样可能会省一点时间,发现还是TLE,最后我把 init 里的 null 初始化放在 while 外面去了,终于以微弱的领先优势绝杀了。。。 = = (3)改的时候,其实最麻烦的是处理我加上去的那个虚拟节点(因为split 限制 left 不为空),它的 s = 0,s_max = -INF(不能影响到它的父亲结点取s_max),它的左儿子是 null,maintain 的时候要单独考虑,因为null 的 s 为0,不然它的 s_max 就变为0了!

好了,以上纯属我个人娱乐,如果占用大家宝贵时间,实在抱歉。。 = =

哎,看了大家过的时间,Splay应该不至于超时,不知道哪里写搓了。。 希望各路神牛路过的时候能指教一下。。 

把两份代码先都贴上来吧。。

栈模拟代码如下:

#include<cstdio>#include<cstring>#include<vector>#include<algorithm>using namespace std;const int INF = 0x0fffffff ;struct Node{    int s,s_max;    int val;    Node(){}    Node(int a,int b,int c) : s(a),s_max(b),val(c) {}};vector <Node> a,b;char str[11];int main(){    int q;    while(~scanf("%d",&q))    {        a.clear();        b.clear();        a.push_back(Node(0,-INF,0));        int x;        while(q--)        {            scanf("%s",str);            if(str[0] == 'I')            {                scanf("%d",&x);                int size = a.size();                a.push_back(Node(a.back().s + x,max(a.back().s_max,a.back().s + x),x));            }            else if(str[0] == 'D')            {                if(a.size()>1)                {                    a.pop_back();                }            }            else if(str[0] == 'L')            {                if(a.size()>1)                {                    int val = a.back().val;                    a.pop_back();                    b.push_back(Node(0,0,val));                }            }            else if(str[0] == 'R')            {                if(b.size()>=1)                {                    int val = b.back().val;                    b.pop_back();                    a.push_back(Node(a.back().s + val,max(a.back().s_max,a.back().s + val),val));                }            }            else            {                scanf("%d",&x);                printf("%d\n",a[x].s_max);            }        }    }    return 0;}


伸展树代码如下(1968ms,汗):

#pragma comment(linker, "/STACK:10240000000000,10240000000000")#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int INF = 0x0fffffff ;struct Node{    Node* ch[2];    int flag;    int v;    int s_max,s;    int size ;    Node(){}    Node(int v,int flag,Node* null): v(v),flag(flag) { ch[0] = ch[1] = null;s = 0;s_max = 0;size = 1;}    int cmp(int x)    {        if(ch[0]->size+1 == x) return -1;        else return x < ch[0]->size+1 ? 0 : 1;    }    void maintain(Node* null)    {        if(flag == 1 && ch[1] == null)        {            size = 1;            s = 0;            s_max = -INF;            return ;        }        size = 1;        size += ch[0]->size + ch[1]->size ;        s = v;        if(ch[0] != null)        {            s += ch[0]->s;            s_max = max(ch[0]->s_max,ch[0]->s + v);            if(ch[1] != null)            {                s += ch[1]->s;                s_max = max(s_max,ch[0]->s + v + ch[1]->s_max);            }        }        else        {            s_max = v;            if(ch[1] != null)            {                s += ch[1]->s;                s_max = max(v,v + ch[1]->s_max);            }        }    }};struct Splay{    Node *root,*null;    int n,pos;    void init()    {        null = new Node;        null->ch[0] = null->ch[1] = null;        null->v = 0;        null->size = 0;        null->s_max = 0;        null->s = 0;    }    void build()    {        root = new Node(0,1,null);        root->s_max = -INF;        n = pos = 1;    }    void rotate(Node* &o,int d)    {        Node* k = o->ch[d^1];o->ch[d^1] = k->ch[d];k->ch[d] = o;        o->maintain(null);k->maintain(null);o = k;    }    void splay(Node* &o,int k)    {        int d = o->cmp(k);        if(d == 1) k -= o->ch[0]->size + 1;        if(d != -1)        {            Node* p = o->ch[d];            int d2 = p->cmp(k);            if(d2 != -1)            {                int k2 = d2==0? k: k - p->ch[0]->size - 1;                splay(p->ch[d2],k2);                if(d == d2)                    rotate(o,d^1);                else rotate(o->ch[d],d);            }            rotate(o,d^1);        }    }    void split(Node* o,int k,Node* &left,Node* &right)    {        splay(o,k);        left = o;        right = o->ch[1];        o->ch[1] = null;        left->maintain(null);    }    Node* merge(Node* left,Node* right)    {        splay(left,left->size);        left->ch[1] = right;        left->maintain(null);        return left;    }    void solve(char str[])    {        int x;        if(str[0] == 'I')        {            n++;            scanf("%d",&x);            Node *mid = new Node(x,0,null);            Node *left,*right,*o;            split(root,pos,left,right);            root = merge(merge(left,mid),right);            pos++;        }        else if(str[0] == 'Q')        {            scanf("%d",&x);            splay(root,x+1);            //debug(root);            printf("%d\n",max(root->ch[0]->s_max,root->ch[0]->s + root->v));        }        else if(str[0] == 'L')        {            if(pos >= 2) pos--;        }        else if(str[0] == 'R')        {            if(pos < n) pos++;        }        else if(pos>1 && str[0] == 'D')        {            n--;            Node *mid,*left,*right,*o;            split(root,pos - 1,left,o);            split(o,1,mid,right);            root = merge(left,right);            pos--;        }        //puts("last");        //debug(root);    }    void debug(Node* o)    {        if(o == null)        {            puts("(null)");            return ;        }        printf("%d|%d|%d(",o->v,o->s_max,o->s);        if(o->ch[0]!=null) printf("%d|%d|%d,",o->ch[0]->v,o->ch[0]->s_max,o->ch[0]->s);        else printf("null,");        if(o->ch[1]!=null) printf("%d|%d|%d",o->ch[1]->v,o->ch[1]->s_max,o->ch[1]->s);        else printf("null");        puts(")");        if(o->ch[0]!=null) debug(o->ch[0]);        if(o->ch[1]!=null) debug(o->ch[1]);    }} sp;char str[11];int main(){    //reopen("D://in.txt","r",stdin);//freopen("D://out1.txt","w",stdout);sp.init();    int n;    while(~scanf("%d",&n))    {        sp.build();        while(n--)        {            scanf("%s",str);            sp.solve(str);        }    }    return 0;}/*11I -5I -3I 9I -3Q 4*/