分块,每一块维护前缀和,观察发现,一次区间加操作对于
L
前,
每个块维护一个凸包(上凸下凸应该都可以,下文以上凸为例),如果这个块被完整覆盖,就打个斜率的标记,否则暴力重构凸包。
询问时在区间里二分,找到一个最大的斜率
(u,v)
使得其加上区间的斜率标记
<0
<script type="math/tex" id="MathJax-Element-792"><0</script>,这时因为上凸,斜率递减,而这之前的斜率加上标记全部
>0
,所以
u
优于其左侧所有点,这条斜率开始之后的斜率加标记全部
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 110000;
const int maxnn = 400;
struct point
{
ll x,y;
point(){}
point(ll _x,ll _y){x=_x;y=_y;}
};
struct node
{
ll s[maxnn];
point p[maxnn];
int pos[maxnn];
int len;
ll k;
}a[maxnn];
ll s[maxn],f[maxn];
int id[maxn],st[maxn],N;
int n,m;
ll multi(point a1,point a2,point x)
{
a1.x-=x.x;a2.x-=x.x;
a1.y-=x.y;a2.y-=x.y;
return a1.x*a2.y-a2.x*a1.y;
}
double get_k(point x,point y)
{
double tx=y.x-x.x,ty=y.y-x.y;
return ty/tx;
}
void up(ll &x,ll y){if(y>x)x=y;}
void _build(int t)
{
a[t].len=a[t].k=f[t]=0;
int len=0;
for(int i=st[t];i<st[t+1];i++)
{
point tmp=point(i-st[t]+1,s[i]);
while(len>1&&multi(a[t].p[len],tmp,a[t].p[len-1])>0) len--;
a[t].p[++len]=tmp;
a[t].pos[len]=i;
}
a[t].len=len;
}
int find_(int t)
{
int l=1,r=a[t].len-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(get_k(a[t].p[mid],a[t].p[mid+1])+(double)a[t].k>0)l=mid+1;
else r=mid-1;
}
return r+1;
}
int main()
{
scanf("%d",&n);N=sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&s[i]); s[i]+=s[i-1];
id[i]=(i-1)/N+1;
}
for(int i=1;i<=id[n];i++)st[i]=(i-1)*N+1;
st[id[n]+1]=n+1;
for(int i=1;i<=id[n];i++) _build(i);
scanf("%d",&m);
while(m--)
{
int x;scanf("%d",&x);
if(!x)
{
int l,r;ll k;scanf("%d%d%lld",&l,&r,&k);
int t1=id[l],t2=id[r];
if(t1==t2)
{
for(int i=st[t1];i<st[t1+1];i++)
s[i]=s[i]+a[t1].k*i+f[t1];
for(int i=l;i<=r;i++)
s[i]+=k*(i-l+1);
for(int i=r+1;i<st[t1+1];i++) s[i]+=(r-l+1)*k;
_build(t1);
for(int i=t1+1;i<=id[n];i++) f[i]+=(r-l+1)*k;
}
else
{
for(int i=st[t1];i<st[t1+1];i++)
s[i]=s[i]+a[t1].k*i+f[t1];
for(int i=l;i<st[t1+1];i++) s[i]+=k*(i-l+1);
_build(t1);
for(int i=t1+1;i<t2;i++)
{
f[i]-=(l-1)*k;
a[i].k+=k;
}
for(int i=st[t2];i<st[t2+1];i++)
s[i]=s[i]+a[t2].k*i+f[t2];
for(int i=st[t2];i<=r;i++) s[i]+=k*(i-l+1);
for(int i=r+1;i<st[t2+1];i++) s[i]+=k*(r-l+1);
_build(t2);
for(int i=t2+1;i<=id[n];i++)f[i]+=k*(r-l+1);
}
}
else
{
int l,r; scanf("%d%d",&l,&r);
int t1=id[l],t2=id[r];
if(t1==t2)
{
ll ret=LLONG_MIN;
for(int i=l;i<=r;i++)
up(ret,s[i]+i*a[t1].k+f[t1]);
printf("%lld\n",ret);
}
else
{
ll ret=LLONG_MIN;
for(int i=l;i<st[t1+1];i++)
up(ret,s[i]+i*a[t1].k+f[t1]);
for(int i=st[t2];i<=r;i++)
up(ret,s[i]+i*a[t2].k+f[t2]);
for(int i=t1+1;i<t2;i++)
{
int temp=find_(i); temp=a[i].pos[temp];
up(ret,s[temp]+a[i].k*temp+f[i]);
}
printf("%lld\n",ret);
}
}
}
return 0;
}