BZOJ5089: 最大连续子段和
维护一个序列支持以下操作:区间加,区间求最大子段和。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: 最大连续子段和的更多相关文章
- BZOJ5089 最大连续子段和(分块)
假设所有操作都是对整个序列的.考虑每个子区间,区间和与其被加的值构成一次函数关系.最大子段和相当于多个子区间取最大值,答案显然就在这些一次函数构成的下凸壳上.如果预处理出凸壳,只要在凸壳上暴力跳就可以 ...
- bzoj5089 最大连续子段和 分块+复杂度分析+凸包
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5089 题解 本来打算迟一点再写这个题解的,还有一个小问题没有弄清楚. 不过先写一下存个档吧. ...
- 【bzoj5089】最大连续子段和 分块+单调栈维护凸包
题目描述 给出一个长度为 n 的序列,要求支持如下两种操作: A l r x :将 [l,r] 区间内的所有数加上 x : Q l r : 询问 [l,r] 区间的最大连续子段和. 其中,一 ...
- HDOJ-1003 Max Sum(最大连续子段 动态规划)
http://acm.hdu.edu.cn/showproblem.php?pid=1003 给出一个包含n个数字的序列{a1,a2,..,ai,..,an},-1000<=ai<=100 ...
- HDU 1003:Max Sum(DP,连续子段和)
Max Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Su ...
- HPU 1007: 严格递增连续子段(贪心)
1007: 严格递增连续子段 [模拟] 时间限制: 1 Sec 内存限制: 128 MB提交: 244 解决: 18 统计 题目描述 给定一个有NN个正整数组成的序列,你最多可以改变其中一个元素,可以 ...
- HDU 1003 最大连续子段和
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1003 Max Sum Time Limit: 2000/1000 MS (Java/Others)M ...
- [题解](线段树最大连续子段和)POJ_3667_Hotel
题意:1.求一个最靠左的长x的区间全部为0,并修改为1,输出这个区间的左端点 2.修改一个区间为0 实际上是维护最大连续子段和,原来也写过 大概需要维护一个左/右最大子段和,当前这段最大子段长,再维护 ...
- JDOJ 2982: 最大连续子段和问题
洛谷 P1115 最大子段和 洛谷传送门 JDOJ 2982: 最大连续子段和问题 JDOJ传送门 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入格式 第一行是一个正整数NN, ...
随机推荐
- linux vi 块操作、多窗口
vim 块选择v:字符选择或者行选择[ctrl]+v: 块选择y:将反白的地方复制d:将反白的地方删除 多窗口:sp {filename} 打开一个新的窗口[ctrl]+w+j或者[ctrl]+w+向 ...
- [转]C语言/C++中如何产生随机数
C语言/C++怎样产生随机数:这里要用到的是rand()函数, srand()函数,和time()函数. 需要说明的是,iostream头文件中就有srand函数的定义,不需要再额外引入stdlib. ...
- 260 Single Number III 数组中除了两个数外,其他的数都出现了两次,找出这两个只出现一次的数
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其他所有元素均出现两次. 找出只出现一次的那两个元素.示例:给定 nums = [1, 2, 1, 3, 2, 5], 返回 [3, 5].注 ...
- 网站开发综合技术 第一部分HTML 1.3.2表单
<form id="" name="" method="post/get" action="负责处理的服务端"&g ...
- LDA算法(入门篇)
一. LDA算法概述: 线性判别式分析(Linear Discriminant Analysis, LDA),也叫做Fisher线性判别(Fisher Linear Discriminant ,FLD ...
- ZENCART 二级 分类 展开
zencart首页默认的是只显示一级分类,很多做仿牌外贸的朋友觉得只显示一级分类不好看,也不利于产品展示.怎么让zencart首页显示二级目录?下面分享给大家: 打开文件’includes/class ...
- POJ_1018_(dp)
Communication System Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28273 Accepted: ...
- Java基础(九)--反射
什么是反射? 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性 这种动态获取的信息以及动态调用对象的方法的功能称为反射机制. 反射的前 ...
- BZOJ 2223: [Coci 2009]PATULJCI 主席树
Code: #include<bits/stdc++.h> #define maxn 300001 #define mid ((l+r)>>1) using namespace ...
- (转)vim编辑器操作命令大全-绝对全
周六了,熟悉熟悉vim 命令 学习链接: vim命令大全 http://blog.csdn.net/scaleqiao/article/details/45153379 vim命令小技巧 http:/ ...