假设所有操作都是对整个序列的。考虑每个子区间,区间和与其被加的值构成一次函数关系。最大子段和相当于多个子区间取最大值,答案显然就在这些一次函数构成的下凸壳上。如果预处理出凸壳,只要在凸壳上暴力跳就可以回答询问了,因为加的都是正数,并且斜率不同的一次函数数量是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<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),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-)/(y.k-x.k)+;}
struct hull
{
line a[BLOCK];int cnt,cur;
void ins(line x){while (cnt&&x.b>=a[cnt].b||cnt>&&x.f(cross(a[cnt],a[cnt-]))>a[cnt].f(cross(a[cnt],a[cnt-]))) cnt--;a[++cnt]=x;}
void clear(){cnt=,cur=,ins((line){,});}
void jump(ll x){while (cur<cnt&&a[cur].f(x)<a[cur+].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=;
sum=;for (int i=L;i<=R;i++) sum+=a[i];
ll x=;pre.clear();
for (int i=L;i<=R;i++) pre.ins((line){i-L+,x+=a[i]});
x=;suf.clear();
for (int i=R;i>=L;i--) suf.ins((line){R-i+,x+=a[i]});
seq.clear();
for (int k=;k<=R-L+;k++)
{
ll s=-inf;x=;for (int i=L;i<=L+k-;i++) x+=a[i];
for (int i=L+k-;i<=R;i++) s=max(s,x),x+=a[i+]-a[i-k+];
seq.ins((line){k,s});
}
}
void add(int x){sum+=1ll*(R-L+)*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=,ans=;
for (int i=l;i<=r;i++)
{
s+=tmp[i];
if (s<) s=;
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=*pow(n,1.0/)+;num=(n-)/block+;
for (int i=;i<=n;i++) a[i]=read();
for (int i=;i<=num;i++)
{
f[i].L=f[i-].R+,f[i].R=min(n,f[i].L+block-);
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]+;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]+;i<pos[r];i++) ans=max(ans,f[i].maxseq());
for (int i=pos[l];i<=pos[r];i++) PRE[i]=SUF[i]=;
s=;for (int i=f[pos[l]].R;i>=l;i--) s+=tmp[i],SUF[pos[l]]=max(SUF[pos[l]],s);
s=;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]+;i<pos[r];i++) SUF[i]=max(f[i].maxsuf(),SUF[i-]+f[i].sum);
for (int i=pos[r]-;i>pos[l];i--) PRE[i]=max(f[i].maxpre(),PRE[i+]+f[i].sum);
for (int i=pos[l];i<pos[r];i++) ans=max(ans,SUF[i]+PRE[i+]);
printf(LL,ans);
}
}
}
return ;
}

BZOJ5089 最大连续子段和(分块)的更多相关文章

  1. bzoj5089 最大连续子段和 分块+复杂度分析+凸包

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5089 题解 本来打算迟一点再写这个题解的,还有一个小问题没有弄清楚. 不过先写一下存个档吧. ...

  2. 【bzoj5089】最大连续子段和 分块+单调栈维护凸包

    题目描述 给出一个长度为 n 的序列,要求支持如下两种操作: A  l  r  x :将 [l,r] 区间内的所有数加上 x : Q  l  r : 询问 [l,r] 区间的最大连续子段和. 其中,一 ...

  3. BZOJ5089: 最大连续子段和

    维护一个序列支持以下操作:区间加,区间求最大子段和.n<=50000,m<=50000. 我TM再也不写分块了... 先分块,对于块整体加的操作,假设块里面有若干二元组(x,y),表示一个 ...

  4. HDOJ-1003 Max Sum(最大连续子段 动态规划)

    http://acm.hdu.edu.cn/showproblem.php?pid=1003 给出一个包含n个数字的序列{a1,a2,..,ai,..,an},-1000<=ai<=100 ...

  5. HDU 1003:Max Sum(DP,连续子段和)

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su ...

  6. HPU 1007: 严格递增连续子段(贪心)

    1007: 严格递增连续子段 [模拟] 时间限制: 1 Sec 内存限制: 128 MB提交: 244 解决: 18 统计 题目描述 给定一个有NN个正整数组成的序列,你最多可以改变其中一个元素,可以 ...

  7. HDU 1003 最大连续子段和

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1003 Max Sum Time Limit: 2000/1000 MS (Java/Others)M ...

  8. [题解](线段树最大连续子段和)POJ_3667_Hotel

    题意:1.求一个最靠左的长x的区间全部为0,并修改为1,输出这个区间的左端点 2.修改一个区间为0 实际上是维护最大连续子段和,原来也写过 大概需要维护一个左/右最大子段和,当前这段最大子段长,再维护 ...

  9. JDOJ 2982: 最大连续子段和问题

    洛谷 P1115 最大子段和 洛谷传送门 JDOJ 2982: 最大连续子段和问题 JDOJ传送门 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入格式 第一行是一个正整数NN, ...

随机推荐

  1. TensorFlow Python2.7环境下的源码编译(三)编译

    一.源代码编译 这里要为仅支持 CPU 的 TensorFlow 构建一个 pip 软件包,需要调用以下命令: $ bazel build --cxxopt="-D_GLIBCXX_USE_ ...

  2. [Lua] 迭代器 闭合函数 与 泛型for

    首先看看一下闭合函数(closure),见如下代码: function newCounter() local i = 0 -- 非局部变量(non-local variable) return fun ...

  3. linux文件种类及其扩展名

    文件种类 普通文件(ls -al出来第一列为-) 纯文本文件(ASCII):linux系统中最多的一种文件类型,可以使用cat直接读取: 二进制文件(binary):linux下面的可执行文件: 数据 ...

  4. thymeleaf 使用javascript定义数组报错

    js中免不了的要用的数组,一维的二维的三维的 但是当用到thymeleaf作为模版时候会有一些坑,导致数组不能用 org.thymeleaf.exceptions.TemplateProcessing ...

  5. node上的__dirname和./的区别

    概要 Node.js 中,__dirname 总是指向被执行 js 文件的绝对路径,所以当你在 /d1/d2/myscript.js 文件中写了 __dirname, 它的值就是 /d1/d2 . 相 ...

  6. 慢吞吞的pip切换源

    http://blog.csdn.net/gz_liuyun/article/details/52778198

  7. No.1_NABCD模型分析

        Reminder 之 NABCD模型分析           定位 多平台的闹钟提醒软件. 在安卓市场发布软件,发布后一周的用户量为1000.           N (Need 需求) 这个 ...

  8. 冲刺One之站立会议7 /2015-5-20

    2015-5-20 在登陆成功之后要实现的是聊天界面的交互过程,不同的IP进行信息和数据的传递,这方面我们上学期Java实验里面有过相关的内容,我们把它拿过来改了一下格式,试着看能不能成功,目前还没实 ...

  9. Java 反射 不定参数bug

    遇到的第一个关于反射的bug:java.lang.IllegalArgumentException: wrong number of arguments的问题解析如下: 1.错误bug wrong n ...

  10. 【流程图】购物车、三级菜单、sed替换