假设所有操作都是对整个序列的。考虑每个子区间,区间和与其被加的值构成一次函数关系。最大子段和相当于多个子区间取最大值,答案显然就在这些一次函数构成的下凸壳上。如果预处理出凸壳,只要在凸壳上暴力跳就可以回答询问了,因为加的都是正数,并且斜率不同的一次函数数量是O(n)的。暴力建凸壳的复杂度是O(n2)的。
那么考虑分块。每个块预处理出凸壳。区间加时,对于整块在凸壳上暴跳,零散部分暴力重构。查询时合并区间,类似于单点加的线段树做法,维护块内最大前缀和、最大后缀和。块大小取n1/3时最优。
造凸壳写挂调了1h,退役了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 50010 #define NUM 2000 #define BLOCK 100 #define inf 10000000000000000ll char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,pos[N],num,block; ll a[N],tmp[N],PRE[N],SUF[N]; struct line { ll k,b; ll f(ll x){return k*x+b;} }; ll cross(line x,line y){return (x.b-y.b-1)/(y.k-x.k)+1;} struct hull { line a[BLOCK];int cnt,cur; void ins(line x){while (cnt&&x.b>=a[cnt].b||cnt>1&&x.f(cross(a[cnt],a[cnt-1]))>a[cnt].f(cross(a[cnt],a[cnt-1]))) cnt--;a[++cnt]=x;} void clear(){cnt=0,cur=1,ins((line){0,0});} void jump(ll x){while (cur<cnt&&a[cur].f(x)<a[cur+1].f(x)) cur++;} ll get(ll x){return a[cur].f(x);} }; struct data { hull pre,suf,seq;int L,R;ll lazy,sum; void build() { for (int i=L;i<=R;i++) a[i]+=lazy;lazy=0; sum=0;for (int i=L;i<=R;i++) sum+=a[i]; ll x=0;pre.clear(); for (int i=L;i<=R;i++) pre.ins((line){i-L+1,x+=a[i]}); x=0;suf.clear(); for (int i=R;i>=L;i--) suf.ins((line){R-i+1,x+=a[i]}); seq.clear(); for (int k=1;k<=R-L+1;k++) { ll s=-inf;x=0;for (int i=L;i<=L+k-1;i++) x+=a[i]; for (int i=L+k-1;i<=R;i++) s=max(s,x),x+=a[i+1]-a[i-k+1]; seq.ins((line){k,s}); } } void add(int x){sum+=1ll*(R-L+1)*x,lazy+=x,pre.jump(lazy),suf.jump(lazy),seq.jump(lazy);} ll maxpre(){return pre.get(lazy);} ll maxsuf(){return suf.get(lazy);} ll maxseq(){return seq.get(lazy);} }f[NUM]; ll getseq(int l,int r) { ll s=0,ans=0; for (int i=l;i<=r;i++) { s+=tmp[i]; if (s<0) s=0; ans=max(ans,s); } return ans; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5089.in","r",stdin); freopen("bzoj5089.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read();block=2*pow(n,1.0/3)+1;num=(n-1)/block+1; for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=num;i++) { f[i].L=f[i-1].R+1,f[i].R=min(n,f[i].L+block-1); for (int j=f[i].L;j<=f[i].R;j++) pos[j]=i; f[i].build(); } while (m--) { char c=getc(); if (c=='A') { int l=read(),r=read(),x=read(); if (pos[l]==pos[r]) { for (int i=l;i<=r;i++) a[i]+=x; f[pos[l]].build(); } else { for (int i=pos[l]+1;i<pos[r];i++) f[i].add(x); for (int i=l;i<=f[pos[l]].R;i++) a[i]+=x;f[pos[l]].build(); for (int i=f[pos[r]].L;i<=r;i++) a[i]+=x;f[pos[r]].build(); } } else { int l=read(),r=read(); if (pos[l]==pos[r]) { for (int i=l;i<=r;i++) tmp[i]=a[i]+f[pos[l]].lazy; printf(LL,getseq(l,r)); } else { for (int i=l;i<=f[pos[l]].R;i++) tmp[i]=a[i]+f[pos[l]].lazy; for (int i=f[pos[r]].L;i<=r;i++) tmp[i]=a[i]+f[pos[r]].lazy; ll ans=max(getseq(l,f[pos[l]].R),getseq(f[pos[r]].L,r)),s; for (int i=pos[l]+1;i<pos[r];i++) ans=max(ans,f[i].maxseq()); for (int i=pos[l];i<=pos[r];i++) PRE[i]=SUF[i]=0; s=0;for (int i=f[pos[l]].R;i>=l;i--) s+=tmp[i],SUF[pos[l]]=max(SUF[pos[l]],s); s=0;for (int i=f[pos[r]].L;i<=r;i++) s+=tmp[i],PRE[pos[r]]=max(PRE[pos[r]],s); for (int i=pos[l]+1;i<pos[r];i++) SUF[i]=max(f[i].maxsuf(),SUF[i-1]+f[i].sum); for (int i=pos[r]-1;i>pos[l];i--) PRE[i]=max(f[i].maxpre(),PRE[i+1]+f[i].sum); for (int i=pos[l];i<pos[r];i++) ans=max(ans,SUF[i]+PRE[i+1]); printf(LL,ans); } } } return 0; }