[日常摸鱼]Vijos1083小白逛公园-线段树

题意:单点修改,询问区间最大子段和,$n\leq 5e5$

 


 

 

考虑分治的方法$O(nlogn)$求一次最大子段和的做法,我们是根据中点分成左右两个区间,那么整个区间的答案要么是左边答案,要么是右边答案,要么是左边的最大后缀和加上右边的最大前缀和。而一个区间的最大前缀和又会等于它左区间的最大前缀和或者是左区间的和加上右区间最大前缀和。

基于这种思想我们就有了一种动态求最大字段和的算法了,区间和,前缀后缀和,都可以直接用线段树维护,用这些信息就能求出最大子段和了。

注意询问的时候应该把整个结点的信息储存下来,因为我们要查询的是一个区间而不是一整段,如果直接返回结点的答案话可能会把询问区间外面的信息也算进来。

 

#include<cstdio>
typedef long long lint;
const int N=500005;
inline lint read()
{
    lint s=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){s=s*10+c-'0';c=getchar();}
    return s*f;
}
struct node
{
    lint ls,rs,key,s;
    node(lint a=0,lint b=0,lint c=0,lint d=0):ls(a),rs(b),key(c),s(d){}
};
int n,m;
lint ls[N<<2],rs[N<<2],key[N<<2],s[N<<2],v[N];

inline void swap(int &a,int &b){int t=a;a=b;b=t;} 
inline lint max(lint a,lint b){return a>b?a:b;}
#define lson (o<<1)
#define rson (o<<1|1)
inline void push_up(int o)
{
    ls[o]=max(ls[lson],s[lson]+ls[rson]);
    rs[o]=max(rs[rson],s[rson]+rs[lson]);
    s[o]=s[lson]+s[rson];
    key[o]=max(max(key[lson],key[rson]),rs[lson]+ls[rson]);
}
inline void build(int o,int l,int r)
{
    if(l==r)
    {
        ls[o]=rs[o]=key[o]=s[o]=v[l];
        return;
    }int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
    push_up(o);
}
inline void modify(int o,int l,int r,int q,lint val)
{
    if(l==r)
    {
        ls[o]=rs[o]=key[o]=s[o]=val;
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=q)modify(lson,l,mid,q,val);
    else modify(rson,mid+1,r,q,val);
    push_up(o);
}
inline node query(int o,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)return node(ls[o],rs[o],key[o],s[o]);
    int mid=(l+r)>>1,op=0;node L,R,ans;
    if(mid>=ql)L=query(lson,l,mid,ql,qr),op++;
    if(mid+1<=qr)R=query(rson,mid+1,r,ql,qr),op+=2;
    if(op==1)return L;if(op==2)return R;
    ans.ls=max(L.ls,L.s+R.ls);ans.rs=max(R.rs,R.s+L.rs);
    ans.s=L.s+R.s;ans.key=max(max(L.key,R.key),L.rs+R.ls);
    return ans;
}

#undef lson
#undef rson

int main()
{
    n=read();m=read();
    for(register int i=1;i<=n;i++)v[i]=read();
    build(1,1,n);
    while(m--)
    {
        int op,a,b;op=read();
        if(op==1)
        {
            a=read();b=read();if(a>b)swap(a,b);
            printf("%lld\n",query(1,1,n,a,b).key);
        }else
        {
            a=read();b=read();
            modify(1,1,n,a,b);
        }
    }
}

 

posted @ 2018-01-16 13:50  yoshinow2001  阅读(112)  评论(0编辑  收藏  举报