BZOJ2388
维护区间加,前缀和最大值
如果把下标看做x,前缀和看做y,就变成了找凸包上最高点的问题
修改整块:维护斜率,首项
修改散块:暴力重构
对最后一个散块后面的影响:整体加上一个数,用标记
Code:
#include<bits/stdc++.h>
#define ill long long
#define INF 1e18
#define db double
using namespace std;
inline int getint(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=100005,sqrr=350;
int num,n,m,id[N],st[sqrr],ed[sqrr],cnt[sqrr];
int ans[sqrr][sqrr],sqr;
ill a[N],fir[sqrr],d[sqrr],add[sqrr];
int sta[N],top;
inline db K(int x,int y){return (db)(a[y]-a[x])/(y-x);}
inline void build(int v){
sta[top=1]=st[v];
for(int i=st[v]+1;i<=ed[v];i++){
while(top>=2 && K(sta[top-1],sta[top])<K(sta[top-1],i)) --top;
sta[++top]=i;
}
sta[0]=0;sta[top+1]=n+1;cnt[v]=top;
for(int i=0;i<=top+1;i++) ans[v][i]=sta[i];
}
inline void pushdown(int x){
ill tmp=fir[x];
for(int i=st[x];i<=ed[x];i++) a[i]+=tmp,tmp+=d[x],a[i]+=add[x];
fir[x]=d[x]=add[x]=0;
}
inline ill calc(int x){
if(x==0 || x==n+1) return -INF;
return a[x]+fir[id[x]]+d[id[x]]*(x-st[id[x]])+add[id[x]];
}
inline ill query(int x){
int ll=1,rr=cnt[x];
while(ll<=rr){
int mid=(ll+rr)>>1;
ill t1=calc(ans[x][mid-1]),t2=calc(ans[x][mid]),t3=calc(ans[x][mid+1]);
if(t1<t2 && t2<t3) ll=mid+1;
else if(t1>t2 && t2>t3) rr=mid-1;
else return t2;
}
}
signed main(){
n=getint();
for(int i=1;i<=n;i++)a[i]=getint()+a[i-1];
a[0]=a[n+1]=-INF;
sqr=sqrt(n),num=(n%sqr?n/sqr+1:n/sqr);
for(int i=1;i<=n;i++)id[i]=(i-1)/sqr+1;
for(int i=1;i<=num;i++)st[i]=(i-1)*sqr+1,ed[i]=min(n,i*sqr);
for(int i=1;i<=num;i++)build(i);
int op,x,y,l,r;
ill k,tmp,res;
m=getint();
while(m--){
op=getint(),x=getint(),y=getint();
l=id[x],r=id[y];
if(!op){
k=getint();
tmp=k*(st[l+1]-x+1);
for(int i=l+1;i<r;i++) fir[i]+=tmp,d[i]+=k,tmp+=sqr*k;
pushdown(l);
tmp=k;
for(int i=x;i<=min(y,ed[l]);i++)
a[i]+=tmp,tmp+=k;
build(l);
if(l!=r){
pushdown(r);
tmp=k*(st[r]-x+1);
for(int i=st[r];i<=y;i++)a[i]+=tmp,tmp+=k;
}
tmp=k*(y-x+1);
for(int i=y+1;i<=ed[r];i++)a[i]+=tmp;
build(r);
for(int i=r+1;i<=num;i++)add[i]+=tmp;
}
else{
res=-INF;
for(int i=l+1;i<r;i++)res=max(res,query(i));
for(int i=x;i<=min(y,ed[l]);i++)res=max(res,calc(i));
if(l!=r)for(int i=st[r];i<=y;i++)res=max(res,calc(i));
printf("%lld\n",res);
}
}
return 0;
}