JDOJ-1862: [NOI2005]维护序列 Splay

[文章目录]

Description

这是我写的第二道splay,由于小细节,耗时比较大。不过A了还是很开心的。

插入,删除,修改,翻转,求和没得说。

不过反转要注意一下在标记后需要更新一下root->rs和root,由于还有区间最大子序列,所以需要更新,并不像文艺平衡树那样,只更新size,还可以省略。

求和最大的子序列的splay(是不是想到了小白逛公园233),所以我们维护几个连续子序列最大值。

1.mxs,表示当前节点代表的子树区间中和最大的子序列(不可以没有元素)

2.mxl,表示包含左节点的和最大子序列(可以没有元素)

3.mxr,表示包含右节点的序列(可以无元素)

然后就得到了递推式:

mxs=max(ls->mxs , rs->mxs , ls->mxr+val+rs->mxl);

mxl=max(ls->mxl , ls->sum+val+mxr->mxl);

mxr=max(rs->mxr , rs->sum+val+ls->mxr);

由于mxl和mxr可以为0,所以不用考虑区间端点在val左右时的情况。

然后就是各种考码力的东西。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int a[501000];
int n,m;
char st[100];
int pos,tot,c;
int read()//加负号的读入优化
{
    int re=0,f=1;  char gc=getchar();
    while(gc<'0'||gc>'9'){if(gc=='-') f=-f;    gc=getchar();}
    while(gc>='0'&&gc<='9')   re=(re<<1)+(re<<3)+gc-'0',gc=getchar();
    return re*f;
}
struct node
{
    node *fa,*ls,*rs;
    int val,sum,size,mxl,mxr,mxs;
    bool tur;//旋转标记
    int chag;//更改标记
    node(int x);
    void push_up();
    void push_down();
    void reverse();
    void make_same(int x);
}*null=new node(0xefefefef),*root;
node :: node(int x)//直接初始化的时候将点权赋上
{
    fa=ls=rs=null;
    sum=null?x:0;//null的sum一定为0
    mxs=val=x;
    tur=false;
    mxl=mxr=max(0,x);
    chag=-1100;
    size=null?1:0;//
}

void node :: reverse()
{
    swap(ls,rs);
    swap(mxl,mxr);//这两个也要换,不过在第一次WA的时候就发现了
    tur^=1;
}
void node :: make_same(int x)//写这种函数的时候应该看结构体定义了啥,每个的含义都是啥
{
    val=chag=x;
    sum=x*size;
    mxr=mxl=max(sum,0);
    mxs=max(x,sum);
}
void node :: push_up()//向上修改
{
    size=ls->size+rs->size+1;
    mxl=max(ls->mxl,ls->sum+val+rs->mxl);
    mxr=max(rs->mxr,rs->sum+val+ls->mxr);
    mxs=max(max(ls->mxs,rs->mxs),ls->mxr+val+rs->mxl);
    sum=ls->sum+val+rs->sum;
}
void node :: push_down()//下传标记
{
    if(tur)
    {
        if(ls!=null)ls->reverse();
        if(rs!=null)rs->reverse();
        tur=0;
    }
    if(chag!=-1100)
    {
        if(ls!=null)ls->make_same(chag);
        if(rs!=null)rs->make_same(chag);
        chag=-1100;
    }
}
node* build(int l,int r)
{
    if(l>r) return null;
    int mid=l+r>>1;
    node *re=new node(a[mid]);
    re->ls=build(l,mid-1);
    re->rs=build(mid+1,r);
    re->ls->fa=re;re->rs->fa=re;
    re->push_up();
    return re;
}

void initialize()//初始化
{
    root=new node(0);//由于val赋值为0,所以查询mxs时要更改区间
    root->rs=new node(0);
    root->rs->ls=build(1,n);
    root->rs->ls->fa=root->rs;
    root->rs->fa=root;
    root->rs->push_up();
    root->push_up();
}
void zig(node *x)
{
    node *y=x->fa;
    y->ls=x->rs;
    x->rs->fa=y;
    x->rs=y;
    x->fa=y->fa;
    if(y==y->fa->ls) y->fa->ls=x;
    else if(y==y->fa->rs) y->fa->rs=x;
    y->fa=x;
    y->push_up();
    x->push_up();
    if(y==root) root=x;
}
void zag(node *x)
{
    node *y=x->fa;
    y->rs=x->ls;
    x->ls->fa=y;
    x->ls=y;
    x->fa=y->fa;
    if(y==y->fa->ls) y->fa->ls=x;
    else if(y==y->fa->rs) y->fa->rs=x;
    y->fa=x;
    y->push_up();//注意顺序
    x->push_up();
    if(y==root) root=x;
}
void splay(node *x,node *tar)
{
    while(1)
    {
        node *y=x->fa,*z=y->fa;
        if(y==tar) break;
        if(z==tar)
        {
            if(x==y->ls) zig(x);
            else zag(x);
            break;
        }
        if(x==y->ls)
        {
            if(y==z->ls) zig(x),zig(x);
            else zig(x),zag(x);
        }
        else
        {
            if(y==z->rs) zag(x),zag(x);
            else zag(x),zig(x);
        }
    }
}
void find(node *x,int y,node *z)
{
    while(1)
    {
        x->push_down();//在这里下传了,splay时就不用了
        int tmp=x->ls->size;
        if(y<=tmp) x=x->ls;
        else 
        {
            y-=tmp;
            if(y==1) break;
            y--;
            x=x->rs;
        }
    }
    splay(x,z);
}
void Free(node *x)//一定要释放内存,else MLE+1
{
    if(x==null) return ;
    Free(x->ls);
    Free(x->rs);
    free(x);
}
/*void dfs(node *x)
{
    if(x==null) return ;
    x->push_down();
    dfs(x->ls);
    printf("%d: sum%d size%d mxL%d mxR%d mxs%d\n   tur%d chag%d ls%d rs%d\n",x->val,x->sum,x->size,x->mxl,x->mxr,x->mxs,x->tur,x->chag,x->ls->val,x->rs->val);
    dfs(x->rs);
}*/
//调试用的,感觉不错哦233
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) a[i]=read();
    initialize();
    while(m--)
    {
        scanf("%s",st+1);
        switch(st[3])
        {
            case 'S'://添加
            {
                pos=read();tot=read();
                for(int i=1;i<=tot;i++) a[i]=read();
                find(root,pos+1,null);
                find(root,pos+2,root);
                root->rs->ls=build(1,tot);
                root->rs->ls->fa=root->rs;
                root->rs->push_up();//
                root->push_up();
                break;
            }
            case 'L'://删除
            {
                pos=read();tot=read();
                find(root,pos,null);
                find(root,pos+tot+1,root);
                node *tmp=root->rs->ls;//
                root->rs->ls=null;
                root->rs->push_up();//
                root->push_up();
                Free(tmp);//释放内存
                break;
            }
            case 'K'://改成相同的
            {
                pos=read();tot=read();c=read();
                find(root,pos,null);
                find(root,pos+tot+1,root);
                root->rs->ls->make_same(c);//不是简单chag=c标记
                root->rs->push_up();//啊啊啊啊啊,重中之重
                root->push_up();
                break;
            }
            case 'V'://反转
            {
                pos=read();tot=read();
                find(root,pos,null);
                find(root,pos+tot+1,root);
                root->rs->ls->reverse();//
                root->rs->push_up();//重中之重,一顿神调
                root->push_up();
                break;
            }
            case 'T'://求和
            {
                pos=read();tot=read();
                find(root,pos,null);
                find(root,pos+tot+1,root);
                printf("%d\n",root->rs->ls->sum);//不用向上修改了233
                break;
            }
            case 'X':
            {
                find(root,1,null);//啊啊啊啊啊,最后WA的一个点
                find(root,root->size,root);
                printf("%d\n",root->rs->ls->mxs);
                break;
            }
        }
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注