「SCOI 2018 D2T1」Pipi 酱的日常

传送门


problem

给定 n n n 个数,第 i ( 1 ≤ i ≤ n ) i(1\le i\le n) i(1in) 个位置上的值为 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 3n,m105


solution

由于会有三个绝对值的变化,设 ∣ a ∣ + ∣ b ∣ + ∣ c ∣ → ∣ a + u ∣ + ∣ b + u ∣ + ∣ c + u ∣ |a|+|b|+|c|\rightarrow |a+u|+|b+u|+|c+u| a+b+ca+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+vav+b+v+c+v+a+vbv+c+vavbv+c+v+a+v+b+vcvav+b+vcv+a+vbvcvavbvcv=a+b+c+3v=a+b+c+v=ab+c+v=ab+cv=a+bc+v=a+bcv=abcv=abc3v

暴力维护一下以上 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值