problem
给定 n n n 个数,第 i ( 1 ≤ i ≤ n ) i(1\le i\le n) i(1≤i≤n) 个位置上的值为 x i x_i xi,有 m m m 个操作,操作有以下两种:
- 1 pos v:将 x x x 数组中位置 p o s pos pos 上的数字改为 v v v;
- 2 l r u:选择 x x x 数组 [ l , r ] [l,r] [l,r] 中的某连续三个数加 u u u,新得到的数组称为 y y y,求所有可能形成的 y y y 数组的各元素绝对值之和的最大值(操作 2 2 2 不会改变 x x x 数组)。
数据范围: 3 ≤ n , m ≤ 1 0 5 3\le n,m\le 10^5 3≤n,m≤105。
solution
由于会有三个绝对值的变化,设 ∣ a ∣ + ∣ b ∣ + ∣ c ∣ → ∣ a + u ∣ + ∣ b + u ∣ + ∣ c + u ∣ |a|+|b|+|c|\rightarrow |a+u|+|b+u|+|c+u| ∣a∣+∣b∣+∣c∣→∣a+u∣+∣b+u∣+∣c+u∣,考虑暴力拆开:
+ a + v + b + v + c + v = a + b + c + 3 v − a − v + b + v + c + v = − a + b + c + v + a + v − b − v + c + v = a − b + c + v − a − v − b − v + c + v = − a − b + c − v + a + v + b + v − c − v = a + b − c + v − a − v + b + v − c − v = − a + b − c − v + a + v − b − v − c − v = a − b − c − v − a − v − b − v − c − v = − a − b − c − 3 v \begin{aligned} +a+v+b+v+c+v&=a+b+c+3v\\ -a-v+b+v+c+v&=-a+b+c+v\\ +a+v-b-v+c+v&=a-b+c+v\\ -a-v-b-v+c+v&=-a-b+c-v\\ +a+v+b+v-c-v&=a+b-c+v\\ -a-v+b+v-c-v&=-a+b-c-v\\ +a+v-b-v-c-v&=a-b-c-v\\ -a-v-b-v-c-v&=-a-b-c-3v \end{aligned} +a+v+b+v+c+v−a−v+b+v+c+v+a+v−b−v+c+v−a−v−b−v+c+v+a+v+b+v−c−v−a−v+b+v−c−v+a+v−b−v−c−v−a−v−b−v−c−v=a+b+c+3v=−a+b+c+v=a−b+c+v=−a−b+c−v=a+b−c+v=−a+b−c−v=a−b−c−v=−a−b−c−3v
暴力维护一下以上 8 8 8 种结果,最后的答案一定是最大的那个。用线段树维护即可。
时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
code
#include<bits/stdc++.h>
#define N 100005
#define ll long long
using namespace std;
int n,m;
ll a[N],SUM,val,ans;
int K[8][4]={
1, 1, 1, 3,
1, 1,-1, 1,
1,-1, 1, 1,
-1, 1, 1, 1,
1,-1,-1,-1,
-1, 1,-1,-1,
-1,-1, 1,-1,
-1,-1,-1,-3
};
ll Abs(ll x) {return x>0?x:-x;}
namespace SGT{
ll mx[N<<2][10];
void pushup(int root){
for(int i=0;i<8;++i)
mx[root][i]=max(mx[root<<1][i],mx[root<<1|1][i]);
}
#define mid ((l+r)>>1)
void build(int root,int l,int r){
if(l==r){
for(int i=0;i<8;++i)
mx[root][i]=K[i][0]*a[l]+K[i][1]*a[l+1]+K[i][2]*a[l+2]-Abs(a[l])-Abs(a[l+1])-Abs(a[l+2]);
return;
}
build(root<<1,l,mid),build(root<<1|1,mid+1,r);
pushup(root);
}
void Modify(int root,int l,int r,int pos){
if(l==r){
for(int i=0;i<8;++i)
mx[root][i]=K[i][0]*a[l]+K[i][1]*a[l+1]+K[i][2]*a[l+2]-Abs(a[l])-Abs(a[l+1])-Abs(a[l+2]);
return;
}
if(pos<=mid) Modify(root<<1,l,mid,pos);
else Modify(root<<1|1,mid+1,r,pos);
pushup(root);
}
ll Query(int root,int l,int r,int x,int y,int id){
if(l>=x&&r<=y) return mx[root][id];
if(y<=mid) return Query(root<<1,l,mid,x,y,id);
if(x> mid) return Query(root<<1|1,mid+1,r,x,y,id);
return max(Query(root<<1,l,mid,x,y,id),Query(root<<1|1,mid+1,r,x,y,id));
}
void update(int pos){
if(pos>=1&&pos<=n-2) Modify(1,1,n-2,pos);
if(pos>=2&&pos<=n-1) Modify(1,1,n-2,pos-1);
if(pos>=3&&pos<=n ) Modify(1,1,n-2,pos-2);
}
#undef mid
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]),SUM+=Abs(a[i]);
SGT::build(1,1,n-2);
int op,pos,l,r;
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d%lld",&pos,&val);
SUM-=Abs(a[pos]),a[pos]=val,SUM+=Abs(val),SGT::update(pos);
}
else{
scanf("%d%d%lld",&l,&r,&val),ans=-1e15;
for(int i=0;i<8;++i) ans=max(ans,SGT::Query(1,1,n-2,l,r-2,i)+K[i][3]*val);
printf("%lld\n",ans+SUM);
}
}
return 0;
}