维护一个序列支持以下操作:区间加,区间求最大子段和。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. srand()

    //第一次:5 0 第二次:5 16 srand(); //seed为常数,则每次运行产生的随机数一样 printf(); //产生的随机数都是一样的,都是5 srand(time(NULL)); p ...

  2. 【转】Linux系统编程---dup和dup2详解

    正常的文件描述符: 在linux下,通过open打开以文件后,会返回一个文件描述符,文件描述符会指向一个文件表,文件表中的节点指针会指向节点表.看下图: 打开文件的内核数据结构 dup和dup2两个函 ...

  3. VMWare虚拟网络编辑

    VMWare虚拟网络编辑记录. 点击"编辑->虚拟网络编辑器" 在网卡列表中选择"VMnet8"查看目前设置,点击右下角的更改设置进行网络修改. 备注:更 ...

  4. c++类的内存布局

    问题: 考察了reinterpret_cast和static_cast的区别.顺道发现了一个可以查看c++内存布局的工具(在VS中). 结果: 前两个输出的地址形同,后一个不同. class A{in ...

  5. 2、ipconfig命令

    该命令能够显示出正在使用的计算机的IP信息情况.这些信息包括IP地址.子网掩码.默认网关(连接本地计算机与Internet的计算机).通过IP地址可以进行扫描.远程管理.入侵检测等.ipconfig命 ...

  6. 创建http对象

    package test; import java.net.HttpURLConnection;import java.net.URL; import javax.servlet.http.HttpS ...

  7. input checkbox 选择内容输出多少个

    <input type="checkbox" name="qId" onclick="doit();"/><input t ...

  8. CSS垂直居中和水平居中的几种方法

    垂直居中 方法一 这个方法把div 的显示方式设置为表格,因此我们可以使用表格的 vertical-align属性. <!DOCTYPE html> <html lang=" ...

  9. Redux 中的CombineReducer的函数详解

    combineReducers(reducers) 随着应用变得复杂,需要对 reducer 函数 进行拆分,拆分后的每一块独立负责管理 state 的一部分. combineReducers 辅助函 ...

  10. 左耳听风 ARTS Week 002

    要求:1.每周至少做一个 leetcode 的算法题 2.阅读并点评至少一篇英文技术文章 3.学习至少一个技术技巧 4.分享一篇有观点和思考的技术文章 1.每周至少做一个 leetcode 的算法题 ...