维护一个序列支持以下操作:区间加,区间求最大子段和。n<=50000,m<=50000。

我TM再也不写分块了。。。

先分块,对于块整体加的操作,假设块里面有若干二元组(x,y),表示一个大小x的区间的和为y,那实际就是求kx+y=z的最大值,而y=-kx+z,所以即求经过这些点、斜率不定的直线的最大纵截距。而稍微画个图可知只有经过一个下凸包上的点的直线可能得到最大纵截距,故每个块维护之。由于区间加的数都是正数,所以查询均摊是O(size)的,而找出所有二元组的(x,y)需要O(size^2),均摊一下就size=n的立方根 即可。

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<math.h>
//#include<iostream>
using namespace std; int n,m,q;
#define maxn 50011
#define maxm 55
#define maxt 5011
#define LL long long
LL max(LL a,LL b) {return a>b?a:b;}
LL a[maxn];
struct Block
{
int l,r;
LL add,tot;
int num[maxm],lnum[maxm],rnum[maxm];
LL Max[maxm],lmax[maxm],rmax[maxm];
void down()
{
if (add) for (int i=l;i<=r;i++) a[i]+=add;
add=;
}
double calc(int i,int j) {return 1.0*(Max[i]-Max[j])/(i-j);}
double lcalc(int i,int j) {return 1.0*(lmax[i]-lmax[j])/(i-j);}
double rcalc(int i,int j) {return 1.0*(rmax[i]-rmax[j])/(i-j);}
void build()
{
int len=r-l+; for (int i=;i<=len;i++) Max[i]=-1e18;
for (int i=l;i<=r;i++)
{
LL now=;
for (int j=i;j<=r;j++)
{
now+=a[j];
Max[j-i+]=max(Max[j-i+],now);
}
}
num[]=;
for (int i=;i<=len;i++)
{
while (num[]> && (calc(num[num[]],num[num[]-])<calc(i,num[num[]]))) num[]--;
num[++num[]]=i;
}
num[num[]+]=; lnum[]=;
lmax[]=;
for (int i=;i<=len;i++) lmax[i]=lmax[i-]+a[l+i-];
for (int i=;i<=len;i++)
{
while (lnum[]> && (lcalc(lnum[lnum[]],lnum[lnum[]-])<lcalc(i,lnum[lnum[]]))) lnum[]--;
lnum[++lnum[]]=i;
}
lnum[lnum[]+]=; rnum[]=;
rmax[]=;
for (int i=;i<=len;i++) rmax[i]=rmax[i-]+a[r-i+];
for (int i=;i<=len;i++)
{
while (rnum[]> && (rcalc(rnum[rnum[]],rnum[rnum[]-])<rcalc(i,rnum[rnum[]]))) rnum[]--;
rnum[++rnum[]]=i;
}
rnum[rnum[]+]=; tot=;
for (int i=l;i<=r;i++) tot+=a[i];
}
LL getans()
{
while (num[num[]+]<num[] && calc(num[num[num[]+]+],num[num[num[]+]])>-add)
num[num[]+]++;
return max(num[num[num[]+]]*add+Max[num[num[num[]+]]],0ll);
}
LL getlans()
{
while (lnum[lnum[]+]<lnum[] && lcalc(lnum[lnum[lnum[]+]+],lnum[lnum[lnum[]+]])>-add)
lnum[lnum[]+]++;
return max(lnum[lnum[lnum[]+]]*add+lmax[lnum[lnum[lnum[]+]]],0ll);
}
LL getrans()
{
while (rnum[rnum[]+]<rnum[] && rcalc(rnum[rnum[rnum[]+]+],rnum[rnum[rnum[]+]])>-add)
rnum[rnum[]+]++;
return max(rnum[rnum[rnum[]+]]*add+rmax[rnum[rnum[rnum[]+]]],0ll);
}
}b[maxt]; int bel[maxn],tot;
void modify(int x,int y,int v)
{
if (bel[x]==bel[y])
{
b[bel[x]].down();
for (int i=x;i<=y;i++) a[i]+=v;
b[bel[x]].build();
}
else
{
int z=b[bel[x]].r;
b[bel[x]].down();
for (int i=x;i<=z;i++) a[i]+=v;
b[bel[x]].build();
z=b[bel[y]].l;
b[bel[y]].down();
for (int i=y;i>=z;i--) a[i]+=v;
b[bel[y]].build();
for (int i=bel[x]+;i<bel[y];i++) b[i].add+=v;
}
}
LL query(int x,int y)
{
if (bel[x]==bel[y])
{
b[bel[x]].down();
b[bel[x]].build();
LL ans=,now=;
for (int i=x;i<=y;i++)
{
now+=a[i];
if (now<) now=;
ans=max(ans,now);
}
return ans;
}
else
{
b[bel[x]].down();
b[bel[x]].build();
b[bel[y]].down();
b[bel[y]].build();
int z=b[bel[x]].r;
LL ans=,rans=,now=;
for (int i=x;i<=z;i++)
{
now+=a[i];
if (now<) now=;
ans=max(ans,now);
}
LL tot=;
for (int i=z;i>=x;i--)
{
tot+=a[i];
rans=max(rans,tot);
}
for (int i=bel[x]+;i<bel[y];i++)
{
LL ll=b[i].getlans(),rr=b[i].getrans(),tt=b[i].tot+(b[i].r-b[i].l+)*b[i].add;
ans=max(ans,max(b[i].getans(),ll+rans));
rans=max(,max(rr,rans+tt));
}
z=b[bel[y]].l;
for (int i=z;i<=y;i++)
{
rans+=a[i];
if (rans<) rans=;
ans=max(ans,rans);
}
return ans;
}
}
int main()
{
scanf("%d%d",&n,&q);
m=;
for (int i=;i<=n;i++) bel[i]=(i-)/m+;
tot=bel[n];
for (int i=;i<tot;i++) b[i].l=(i-)*m+,b[i].r=i*m;
b[tot].l=(tot-)*m+,b[tot].r=n; for (int i=;i<=n;i++) scanf("%lld",&a[i]);
for (int i=;i<=tot;i++) b[i].build(); char id[];int x,y,z;
while (q--)
{
scanf("%s",id);
if (id[]=='A')
{
scanf("%d%d%d",&x,&y,&z);
modify(x,y,z);
}
else
{
scanf("%d%d",&x,&y);
printf("%lld\n",query(x,y));
}
}
return ;
}

我就是死外边,从这里跳下去,我也不再写分块!

BZOJ5089: 最大连续子段和的更多相关文章

  1. BZOJ5089 最大连续子段和(分块)

    假设所有操作都是对整个序列的.考虑每个子区间,区间和与其被加的值构成一次函数关系.最大子段和相当于多个子区间取最大值,答案显然就在这些一次函数构成的下凸壳上.如果预处理出凸壳,只要在凸壳上暴力跳就可以 ...

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

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

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

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

  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. 再谈 webpack build 及 加载优化

    之前项目多,事情忙,一直没时间写博客,现在空闲下来了,总结一下 之前讲过了关于 build 压缩文件的方法,有兴趣的可以看下: 点击查看 现在讲讲一个页面的首屏加载速度该如何提升 提前说明 需要 we ...

  2. Vue学习-Element框架

    今天学了一个基于Vue2.0的桌面端组件库Element,号称是全世界最流行的Vue UI框架.感觉学会了之后就变身大牛了有木有. 好了,不吹牛皮了. Element官方文档通俗易懂,框架什么的安装引 ...

  3. Poj 3177 Redundant Paths (双连通分支+节点统计)

    题目描述: 给出一个无向的连通图,问最少加入几条边,才能使所给的图变为无桥的双连通图? 解题思路: 可以求出原图中所有的不包含桥的所有最大连通子图,然后对连通子图进行标记缩点,统计度为1的叶子节点le ...

  4. win10下spark+Python开发环境配置

    Step0:安装好Java ,jdk Step1:下载好: Step2: 将解压后的hadoop和spark设置好环境变量: 在系统path变量里面+: Step3: 使用pip安装 py4j : p ...

  5. 认识 jQuery (第一笔 点出重点)

    1.我们先来讨论一下 jQuery 是什么? 要认识jQuery(简写jQ)首先要知道JavaScript(简写 js),因为jq就是一堆js的函数,是普通的js,只不过jq应用广泛,形成了行业标准[ ...

  6. data和string类型之间的相互转换

    package main; import java.text.SimpleDateFormat;import java.util.Date; import freemarker.core.ParseE ...

  7. 防止按钮button重复提交,点击后失效,10秒后恢复

    <script type="text/javascript"> $(function () {//页面完全加载完后执行 /*防止重复提交 10秒后恢复*/ var is ...

  8. SDK_按键消息的拦截

    按键消息的拦截 拦截是为了在原有功能的基础上增加自己的操作 扩展:当按钮接收到点击消息的时候,响应的是WM_LBUTTONDOWN消息,按钮的会被这个消息打包成一个WM_COMMAND 消息发送给父窗 ...

  9. Redis系列(四)--持久化

    持久化就是将数据的更新异步的保存到磁盘中 持久化方式: 1.快照:某个时间点数据的备份 MySQL dump.Redis RDB 2.写日志:MySQL BinLog.HBASE Hlog.Redis ...

  10. JavaScipt30(第七个案例)(主要知识点:数组some,every,findIndex方法)

    承接上文,这是第7个案例,这个案例没什么说的,主要有三个注意点: 附上项目链接: https://github.com/wesbos/JavaScript30 // 1. slice(begin, e ...