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

题目: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;
}

/*
11
I -5
I -3
I 9
I -3
Q 4
*/


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值