1. 题目

传送门= ̄ω ̄=

大概就是这样:

需要每单个操作(插入、删除算多次操作)$log_2N$以下

2. 题解

丧心病狂の模板题,,,

mmp 调了我三天

主要是这题细节好多的,比如要注意翻转儿子要先下传再打标记(和我以前做法不同)。

具体做法就和线段树(静态)的做法一样,维护左右最大的两边连续区间和,这样就能获得一个子树对应的区间中的最大子段和。我就不做过多赘述了(懒)

总之是个练 splay 的好题啊,再次刷新我打 splay 的方法。

代码:

#include <bits/stdc++.h>
using namespace std;
template<typename _Tp>inline void IN(_Tp&dig)
{
    char c;bool flag=0;dig=0;
    while(c=getchar(),!isdigit(c))if(c=='-')flag=1;
    while(isdigit(c))dig=dig*10+c-'0',c=getchar();
    if(flag)dig=-dig;
}
struct N{int f,s[2],d,sum,lm,rm,mx,rev,tag,sz;}e[500005];
int n,m,data[500005],cnt,root;
char opt[10];
stack<int> st;
int MKN()
{
    int tmp;
    if(st.empty())tmp=++cnt;
    else tmp=st.top(),st.pop();
    memset(&e[tmp],0,sizeof(N)),e[tmp].tag=1e8;
    return tmp;
}
bool pos(int a){return e[e[a].f].s[1]==a;}
void pup(int a)
{
    int l=e[a].s[0],r=e[a].s[1];
    e[a].sz=e[l].sz+e[r].sz+1;
    e[a].sum=e[l].sum+e[r].sum+e[a].d;
    e[a].mx=max(e[l].mx,e[r].mx);
    e[a].mx=max(e[a].mx,e[l].rm+e[a].d+e[r].lm);
    e[a].lm=max(e[l].lm,e[l].sum+e[a].d+e[r].lm);
    e[a].rm=max(e[r].rm,e[r].sum+e[a].d+e[l].rm);
}
void pdown(int a)
{
    int l=e[a].s[0],r=e[a].s[1];
    if(e[a].tag!=1e8)
    {
        if(l)e[l].tag=e[l].d=e[a].tag,e[l].sum=e[a].tag*e[l].sz;
        if(r)e[r].tag=e[r].d=e[a].tag,e[r].sum=e[a].tag*e[r].sz;
        if(e[a].tag>=0)
        {
            if(l)e[l].lm=e[l].rm=e[l].mx=e[l].sum;
            if(r)e[r].lm=e[r].rm=e[r].mx=e[r].sum;
        }
        else
        {
            if(l)e[l].lm=e[l].rm=0,e[l].mx=e[a].tag;
            if(r)e[r].lm=e[r].rm=0,e[r].mx=e[a].tag;
        }
        e[a].tag=1e8;
    }
    if(e[a].rev)
    {
        if(l)e[l].rev^=1,swap(e[l].lm,e[l].rm),swap(e[l].s[0],e[l].s[1]);
        if(r)e[r].rev^=1,swap(e[r].lm,e[r].rm),swap(e[r].s[0],e[r].s[1]);
        e[a].rev=0;
    }
}
void rot(int a)
{
    int f=e[a].f,g=e[f].f,p=pos(a),q=pos(f);
    pdown(f),pdown(a);
    e[f].s[p]=e[a].s[!p],e[a].s[!p]=f,e[f].f=a;
    if(e[f].s[p])e[e[f].s[p]].f=f;
    if(e[a].f=g)e[g].s[q]=a;
    pup(f),pup(a);
}
void splay(int a,int t)
{
    for(;e[a].f!=t;rot(a))if(e[e[a].f].f!=t)
        if(pos(a)^pos(e[a].f))rot(a);
        else rot(e[a].f);
    if(!t)root=a;
}
int build(int l,int r,int fa)
{
    if(l>r)return 0;
    int mid=(l+r)>>1,a=MKN();
    e[a].s[0]=build(l,mid-1,a),e[a].s[1]=build(mid+1,r,a);
    e[a].f=fa,e[a].d=data[mid],pup(a);
    return a;
}
int find_by_order(int k)
{
    int a=root;
    while(a)
    {
        pdown(a);
        if(k<=e[e[a].s[0]].sz)a=e[a].s[0];
        else
        {
            k-=e[e[a].s[0]].sz+1;
            if(!k)return a;
            a=e[a].s[1];
        }
    }
    return 0;
}
void get_part(int&l,int&r,int pos,int tot)
{
    l=find_by_order(pos),r=find_by_order(pos+tot+1);
    splay(l,0),splay(r,l);
}
void work_insert()
{
    int pos,tot,l,r;
    IN(pos),IN(tot);
    for(int i=1;i<=tot;i++)IN(data[i]);
    get_part(l,r,pos+1,0);
    e[r].s[0]=build(1,tot,r),pup(r),pup(root);
}
void del_dfs(int a)
{
    if(!a)return;
    st.push(a),del_dfs(e[a].s[0]),del_dfs(e[a].s[1]);
}
void work_del()
{
    int pos,tot,l,r;
    IN(pos),IN(tot),get_part(l,r,pos,tot);
    del_dfs(e[r].s[0]),e[r].s[0]=0,pup(r),pup(root);
}
void work_update()
{
    int pos,tot,l,r,c,p;
    IN(pos),IN(tot),IN(c),get_part(l,r,pos,tot),p=e[r].s[0];
    if(p)
    {
        e[p].d=e[p].tag=c,e[p].sum=e[p].sz*c;
        if(c>=0)e[p].lm=e[p].rm=e[p].mx=e[p].sum;
        else e[p].lm=e[p].rm=0,e[p].mx=c;
    }
    pup(r),pup(root);
}
void work_rev()
{
    int pos,tot,l,r,p;
    IN(pos),IN(tot),get_part(l,r,pos,tot),p=e[r].s[0];
    if(p)e[p].rev^=1,swap(e[p].lm,e[p].rm),swap(e[p].s[0],e[p].s[1]);
}
void work_sum()
{
    int pos,tot,l,r;
    IN(pos),IN(tot),get_part(l,r,pos,tot);
    printf("%d\n",e[e[r].s[0]].sum);
}
void work_max()
{
    int l=find_by_order(1),r=find_by_order(e[root].sz);
    splay(l,0),splay(r,l),printf("%d\n",e[e[r].s[0]].mx);
}
int main()
{
    IN(n),IN(m);
    for(int i=1;i<=n;i++)IN(data[i+1]);
    e[0].mx=data[1]=-1e8,data[n+2]=1e8,root=build(1,n+2,0);
    while(m--)
    {
        scanf("%s",opt);
        if(opt[0]=='I')work_insert();
        else if(opt[0]=='D')work_del();
        else if(opt[0]=='M')
        {
            if(opt[2]=='K')work_update();
            else work_max();
        }
        else if(opt[0]=='R')work_rev();
        else work_sum();
    }
    return 0;
}
分类: 文章

XZYQvQ

炒鸡辣鸡的制杖蒟蒻一枚QvQ

1 条评论

【题解】 Editor splay BZOJ – 1507 | K-XZY · 2017年12月27日 10:31 下午

[…] 维修数列参见:传送门= ̄ω ̄= […]

发表回复

Avatar placeholder

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