BZOJ5089 最大连续子段和(分块)
假设所有操作都是对整个序列的。考虑每个子区间,区间和与其被加的值构成一次函数关系。最大子段和相当于多个子区间取最大值,答案显然就在这些一次函数构成的下凸壳上。如果预处理出凸壳,只要在凸壳上暴力跳就可以回答询问了,因为加的都是正数,并且斜率不同的一次函数数量是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 最大连续子段和(分块)的更多相关文章
- bzoj5089 最大连续子段和 分块+复杂度分析+凸包
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5089 题解 本来打算迟一点再写这个题解的,还有一个小问题没有弄清楚. 不过先写一下存个档吧. ...
- 【bzoj5089】最大连续子段和 分块+单调栈维护凸包
题目描述 给出一个长度为 n 的序列,要求支持如下两种操作: A l r x :将 [l,r] 区间内的所有数加上 x : Q l r : 询问 [l,r] 区间的最大连续子段和. 其中,一 ...
- BZOJ5089: 最大连续子段和
维护一个序列支持以下操作:区间加,区间求最大子段和.n<=50000,m<=50000. 我TM再也不写分块了... 先分块,对于块整体加的操作,假设块里面有若干二元组(x,y),表示一个 ...
- 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, ...
随机推荐
- Frida----基本代码
代码来自官网:https://www.frida.re/docs/examples/android/ import frida, sys def on_message(message, data): ...
- CSS盒模型 flex
用于网页布局,PC的话,兼容性不够,慎用,手机端的话,神器 整理部分通用的,可以直接复制的,省得下次再写一遍 注意,设为 Flex 布局以后,子元素的float.clear和vertical-alig ...
- SICP读书笔记 2.5
SICP CONCLUSION 让我们举起杯,祝福那些将他们的思想镶嵌在重重括号之间的Lisp程序员 ! 祝我能够突破层层代码,找到住在里计算机的神灵! 目录 1. 构造过程抽象 2. 构造数据抽象 ...
- 数学建模及机器学习算法(一):聚类-kmeans(Python及MATLAB实现,包括k值选取与聚类效果评估)
一.聚类的概念 聚类分析是在数据中发现数据对象之间的关系,将数据进行分组,组内的相似性越大,组间的差别越大,则聚类效果越好.我们事先并不知道数据的正确结果(类标),通过聚类算法来发现和挖掘数据本身的结 ...
- Java SE练习题——求奇数
欢迎来到Java SE练习题频道,我是Fishing,今天我带来的练习题是(做题会有不足之处,可评论,说出更好的方法): 通过键盘输入两个整数,计算这两个整数之间的所有奇数之和,并输出计算结果. 看到 ...
- 小刘的深度学习---Faster RCNN
前言: 对于目标检测Faster RCNN有着广泛的应用,其性能更是远超传统的方法. 正文: R-CNN(第一个成功在目标检测上应用的深度学习的算法) 从名字上可以看出R-CNN是 Faster RC ...
- 2017年10月WEB前端开发实习生面试题总结
从大一开始学习前端,今年大三,10月份开始投简历,陆续收到很多家公司的面试,目前为止的面试通过率是百分之百,总结下面试题. 不定期更新中... 百度第一次 一面 1.AJAX流程 2.promise简 ...
- 王者荣耀交流协会final发布第五次scrum例会
1.例会照片 成员高远博,冉华,王磊,王玉玲,任思佳,袁玥,王磊,王超. master:王磊 2.时间跨度 2017年12月5日 18:00 — 18:21,总计21分钟 3.地点 一食堂二楼沙发座椅 ...
- DFS--障碍在指定时间会消失
哈利被困在了一个魔法花园里.魔法花园是一个 N*M 的矩形,在其中有着许多植物, 这些植物会在时刻 K 的倍数消失. 哈利每单位时间都会选择上.下.左.右四 个方向的其中一个进行移动. #includ ...
- 软件工程实践2018第六次作业——现场UML作图
团队信息 学号 姓名 博客链接 124 王彬(组长) 点击这里 206 赵畅 点击这里 215 胡展瑞 点击这里 320 李恒达 点击这里 131 佘岳昕 点击这里 431 王源 点击这里 206 陈 ...