hdu 4699 Editor(Splay)

题意:对一个数列进行操作,光标位置后面插入一个权值为x的数,删除光标前的那个数,光标左移一位,光标右移一位,求到k位置的最大的前缀和。

Splay在比赛的时候写得太Navie,T了整场。

左移和右移的操作就不说了,删除点的操作是,直接把第pos个点旋转成根结点,然后把这个点删除,将左右两个儿子(如果有)合并成一棵新的树。插入的时候,将pos个点旋转成根结点,然后在根和根的右儿子之间插入这个点。

同时维护sum(区间和),和mx(表示以x为根结点的最大前缀和),就可以解决这道题了。

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

#define LL(x) (ch[x][0])
#define RR(x) (ch[x][1])
#define Kt(x) (ch[ ch[Rt][1] ][0])
#define INF (1<<30)

const int N=1e6+5;

struct SplayTree
{
    int Rt,top;
    int ch[N][2],pre[N],sz[N];

    int key[N],sum[N],mx[N],pos;

    void init()
    {
        top=Rt=pos=0;
        pre[0]=LL(0)=RR(0)=sz[0]=0;
    }

    inline void Link(int x,int y,int f)
    {
        ch[y][f]=x;     pre[x]=y;
    }
    inline void Rotate(int x,int f)
    {
        int y=pre[x],z=pre[y];

        PushDown(y); PushDown(x);

        Link(ch[x][f],y,!f);
        Link(x,z,RR(z)==y);
        Link(y,x,f);

        PushUp(y);
    }
    inline void Splay(int x,int goal)
    {
        while(pre[x]!=goal)
        {
            int y=pre[x],z=pre[y];
            int cx=(LL(y)==x),cy=(LL(z)==y);
            if(z==goal) Rotate(x,cx);
            else
            {
                if(cx==cy) Rotate(y,cy);
                else Rotate(x,cx);
                Rotate(x,cy);
            }
        }
        PushUp(x);
        if(goal==0) Rt=x;
    }
    inline void Select(int K,int goal)
    {
        int x=Rt;
        PushDown(x);
        while(1)
        {
            if(sz[LL(x)]>=K) x=LL(x);
            else if(sz[LL(x)]+1==K) break;
            else K-=sz[LL(x)]+1,x=RR(x);
            PushDown(x);
        }
        Splay(x,goal);
    }
    inline int Join(int r1,int r2)
    {
        if(!r1)
        {
            if(!r2) return 0;
            pre[r2]=0;
            return r2;
        }

        int x=r1;
        while(RR(x)) x=RR(x);
        Splay(x,Rt);

        Link(r2,x,1);
        Rt=x;   pre[x]=0;
        PushUp(x);

        return x;
    }

    void addNode(int valu,int &x,int f)
    {
        x=top++;
        pre[x]=f; LL(x)=RR(x)=0;
        key[x]=valu;
    }
    void PushDown(int x) {}
    void PushUp(int x)
    {
        sz[x]=1; sum[x]=key[x];
        if(LL(x)) sum[x]+=sum[LL(x)],sz[x]+=sz[LL(x)];
        if(RR(x)) sum[x]+=sum[RR(x)],sz[x]+=sz[RR(x)];

        if(LL(x))
        {
            mx[x]=max(mx[LL(x)],sum[LL(x)]+key[x]);
            if(RR(x)) mx[x]=max(mx[x],sum[LL(x)]+key[x]+mx[RR(x)]);
        }
        else
        {
            mx[x]=key[x];
            if(RR(x)) mx[x]=max(mx[x],key[x]+mx[RR(x)]);
        }
    }

    inline void Insert()
    {
        int valu; scanf("%d",&valu);

        int x=++top;
        sz[x]=1; pre[x]=0; LL(x)=RR(x)=0;
        key[x]=valu; sum[x]=0; mx[x]=-INF;
        if(pos==0)
        {
            Link(Rt,x,1);
            Rt=x; PushUp(Rt);
        }
        else
        {
            Select(pos,0);

            int tmp=RR(Rt);
            Link(x,Rt,1); Link(tmp,x,1);
            PushUp(x); PushUp(Rt);
        }
        pos++;
    }
    inline void Delete()
    {
        if(pos==0) return;

        Select(pos,0);
        Rt=Join(LL(Rt),RR(Rt));
        if(Rt) PushUp(Rt);
        pos--;
    }
    void Query()
    {
        int K; scanf("%d",&K);

        K=min(K,sz[Rt]);

        Select(K,0);

        int ans=-1;
        if(LL(Rt)) ans=max(mx[LL(Rt)],sum[LL(Rt)]+key[Rt]);
        else ans=key[Rt];
        printf("%d\n",ans);
    }
    inline void shift(int flag)
    {
        if(flag==0)
        {
            if(pos>0) pos--;
        }
        else
        {
            if(pos<sz[Rt]) pos++;
        }
    }

    void Debug(){ printf("Rt:%d\n",Rt); travel(Rt); }
	void travel(int x)
	{
		if(x==0) return;
		travel(LL(x));
		printf("node:%d,pre:%d,sz:%d,lson:%d,rson:%d,key:%d,sum:%d,mx:%d\n",
				x,pre[x],sz[x],LL(x),RR(x),key[x],sum[x],mx[x]);
		travel(RR(x));
	}

}spt;
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        spt.init();

        for(int i=0;i<n;i++)
        {
            char op[100];
            scanf("%s",op);

            if(op[0]=='L') spt.shift(0);
            else if(op[0]=='R') spt.shift(1);
            else if(op[0]=='I') spt.Insert();
            else if(op[0]=='D') spt.Delete();
            else spt.Query();

           // spt.Debug();
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值