维护一个序列支持以下操作:区间加,区间求最大子段和。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. [App Store Connect帮助]五、管理构建版本(1)上传构建版本概述

    在您添加 App 至您的帐户之后,您可以使用 Xcode 或 Application Loader 来上传构建版本.稍后,您可以随着您 App 的更改上传更多构建版本.分发构建版本以供测试,或提交您的 ...

  2. 小记 vue 打包(build)需要注意的一些事

    记录 vue 项目打包的一些事情 首先声明项目都是由 vue-cli 生成; vue 项目从 dev 切换到 prod 时有很多地方需要注意; 首先是大家最需要注意的 ajax 切换环节 以前一开始用 ...

  3. Visual Studio Code 扩展工具集,记录

    编码 提高效率及校验 Auto Close Tag 自动闭合标签 Auto Rename Tag 自动更改HTML/XML标签,不需要再进行二次修改,减少50%的工作量! Path Intellise ...

  4. TCP流量控制与拥塞解决

    滑动窗口 但要提高网络利用率: nagle算法 - 延迟 慢启动.拥塞避免 发送端主导cwnd init  set  ssthresh  &  cwnd = swnd loop : 网不阻塞 ...

  5. sql剪切数据

    实际项目当中用到的案例,个人笔记. USE [CA-SM]GO/****** Object:  StoredProcedure [dbo].[PG_SM_AddSum]    Script Date: ...

  6. JNDI链接SQLServer数据库步骤

    1.配置context.xml文件 在我们的WebRoot目录下,就是和WEB-INF同级的目录下,新建一个META-INF的目录(假如不存在),在该目录下创建一个context.xml文件,并且在c ...

  7. 北大ACM(POJ1015-Jury Compromise)

    Question:http://poj.org/problem?id=1015 问题点:DP. Memory: 1352K Time: 94MS Language: C++ Result: Accep ...

  8. Java学习4_一些基础4_输入输出_16.5.7

    读取输入: 想从控制台进行输入,首先需要构造一个Scanner对象,并与“标准输入流”System.in关联. Scanner in=new Scanner(System.in); String na ...

  9. Vue指令7:v-model

    可以用 v-model 指令在表单控件元素上创建双向数据绑定. v-model 会忽略所有表单元素的 value.checked.selected 特性的初始值. 因为它会选择 Vue 实例数据来作为 ...

  10. HDU多校Round 4

    Solved:3 rank:405................................. B. Harvest of Apples 知道了S(n,m) 可以o(1)的求S(n - 1, m ...