先考虑询问。
对于边界的点直接更新答案。
对于不在边界上的点:
- 若 ai−1≤ai a i − 1 ≤ a i 且 ai+1≤ai a i + 1 ≤ a i ,增大 ai a i 时答案的增加量为 2x 2 x 。
- 若 ai a i 在 ai−1 a i − 1 和 ai+1 a i + 1 之间,设 t=max(ai−1,ai+1)−ai t = max ( a i − 1 , a i + 1 ) − a i ,若 x≤t x ≤ t 增大 ai a i 时答案不变,否则答案的增加量为 2(x−t) 2 ( x − t ) 。
- 若 ai<ai−1 a i < a i − 1 且 ai<ai+1 a i < a i + 1 ,增大 ai a i 时答案的增加量需要讨论。
发现如果存在第一种情况,选第一种肯定是最优的,可以用线段树记录是否存在。
如果不存在,
[l,r]
[
l
,
r
]
一定是单调或下凸的,也就是说第三种情况最多只会出现一次,找到之后讨论一下就好了。
第二种情况可以用线段树维护最小的
t
t
。
对于修改操作,显然只会影响到 ,直接修改就好了 。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
const ll INF=1e18;
int k,n,m,q,l,r,x;
int a[N];
ll A[N],d[N],sum;
ll c[N<<2][2];
int pos[N<<2];
inline void Update_node(int x,int y){
for(;x<=n;x+=x&-x)A[x]+=y;
}
inline ll Query_node(int x){
ll Ans=0;
for(;x;x-=x&-x)Ans+=A[x];
return Ans;
}
inline ll Abs(ll x){
return x>0?x:-x;
}
inline void Up(int x){
c[x][0]=min(c[x<<1][0],c[x<<1|1][0]);
c[x][1]=max(c[x<<1][1],c[x<<1|1][1]);
if(pos[x<<1]!=-1)pos[x]=pos[x<<1];else pos[x]=pos[x<<1|1];
}
void Build(int x,int l,int r){
if(l==r){
if(l<n&&l>1&&!(a[l]<a[l-1]&&a[l]<a[l+1]))c[x][0]=max(a[l+1]-a[l],a[l-1]-a[l]);else c[x][0]=INF;
if(l>1&&l<n&&a[l]>=a[l-1]&&a[l]>=a[l+1])c[x][1]=1;
if(l>1&&l<n&&a[l]<a[l-1]&&a[l]<a[l+1])pos[x]=l;else pos[x]=-1;
return;
}
int Mid=l+r>>1;
Build(x<<1,l,Mid);Build(x<<1|1,Mid+1,r);
Up(x);
}
ll Query(int x,int l,int r,int L,int R,int y){
if(l>R||r<L)return (y?(y==1?0:-1):INF);
if(l>=L&&r<=R)return y==2?pos[x]:c[x][y];
int Mid=l+r>>1;
ll a=Query(x<<1,l,Mid,L,R,y),b=Query(x<<1|1,Mid+1,r,L,R,y);
if(!y)return min(a,b);
if(y==1)return max(a,b);
return a!=-1?a:b;
}
void Update(int x,int l,int r,int y,int d,ll z){
if(l==r){
if(d==1)c[x][1]=z;else if(d==2)pos[x]=z;else c[x][0]=z;
return;
}
int Mid=l+r>>1;
if(y<=Mid)Update(x<<1,l,Mid,y,d,z);else Update(x<<1|1,Mid+1,r,y,d,z);
Up(x);
}
inline ll Calc(int l,int r,int x){
if(Query(1,1,n,l,r,1))return (x<<1);
ll Ans=-INF;
ll t=Query(1,1,n,l,r,0);
if(t<INF)Ans=max(max(Ans,0ll),x-t<<1);
ll T=Query(1,1,n,l,r,2);
if(T!=-1)Ans=max(Ans,(x<d[T-1]?-x:x-(d[T-1]<<1))+(x<d[T]?-x:x-(d[T]<<1)));
if(l==1)Ans=max(Ans,Abs(Query_node(1)+a[1]+x-Query_node(2)-a[2])-d[1]);
if(r==n)Ans=max(Ans,Abs(Query_node(n)+a[n]+x-Query_node(n-1)-a[n-1])-d[n-1]);
return Ans;
}
inline void Ch(int x){
if(x>1&&x<n){
ll t1=Query_node(x-1)+a[x-1],t2=Query_node(x)+a[x],t3=Query_node(x+1)+a[x+1];
Update(1,1,n,x,1,(t2>=t1&&t2>=t3));
Update(1,1,n,x,2,(t2<t1&&t2<t3?x:-1));
}
if(x<n){
ll t2=Query_node(x)+a[x],t3=Query_node(x+1)+a[x+1];
sum+=Abs(t2-t3)-d[x];d[x]=Abs(t2-t3);
if(x>1&&!(t2<Query_node(x-1)+a[x-1]&&t2<t3))Update(1,1,n,x,0,max(t3-t2,x>1?Query_node(x-1)+a[x-1]-t2:0ll));else Update(1,1,n,x,0,INF);
}
}
inline void Modify(int l,int r,int x){
Update_node(l,x);Update_node(r+1,-x);
Ch(l);if(l>1)Ch(l-1);
if(l<r)Ch(r);if(r<n)Ch(r+1);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<n;i++)d[i]=Abs(a[i]-a[i+1]),sum+=d[i];
Build(1,1,n);
scanf("%d",&q);
while(q--){
scanf("%d%d%d%d",&k,&l,&r,&x);
if(k==1)printf("%I64d\n",sum+Calc(l,r,x));else Modify(l,r,x);
}
return 0;
}