题意
题解
题目让我们求差分和。。
那么我们就直接先差分就可以了
然后差分完,和就是和了。。
然后对于2这个操作,就相当于是两个单点修改
然后一操作,其实就相当于让两个相邻数,假设这两个是
(a,b)
(
a
,
b
)
那么其实就是把他们变成
(a−x,b+x)
(
a
−
x
,
b
+
x
)
然后你考虑一下,改掉他们以后,对答案的贡献就是
|a−x|+|b+x|−|a|−|b|
|
a
−
x
|
+
|
b
+
x
|
−
|
a
|
−
|
b
|
然后看了一下大众的做法,都是发现一个结论
那么就是,如果存在有
a<0,b>0
a
<
0
,
b
>
0
,那么肯定是修改这里是最优的
否则,我们可以就要讨论三种情况,但是注意到,如果没有
a<0,b>0
a
<
0
,
b
>
0
的话,那么
a>0,b<0
a
>
0
,
b
<
0
的情况最多只有一个位置
然后你就找到这个点,暴力询问
然后另外两种情况,可以稍微推一下式子就可以了
但是我觉得这种方法过于麻烦。。要写很多东西,虽然代码都不长。。但是肯定没有我的方法优越啊【自信】
你考虑一下,我们可以对上面这个绝对值暴力展开,获得四种情况
我们分别讨论四种情况可以取到的最大值就可以了
具体来说
你可以把上面这个式子展开成
a−x+b+x−|a|−|b|=a+b−|a|−|b|
a
−
x
+
b
+
x
−
|
a
|
−
|
b
|
=
a
+
b
−
|
a
|
−
|
b
|
然后这个式子的最大值,就是这一段里面
a+b−|a|−|b|
a
+
b
−
|
a
|
−
|
b
|
的最大值了
然后其他也是一样
可能你会问,如果绝对值展开错了怎么办?
其实我们完全不用担心绝对值展开错了的情况
因为他要的是最大值,所以绝对值展开错了肯定是没有展开对的情况优啊
然后这题就变成是一个水题了。。
CODE:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const LL MAX=(1<<30);
const LL N=100005;
LL n,q;
struct qq
{
LL l,r;
LL s1,s2;
LL c,sum;//这个点的值 绝对值的总和
LL a[4];
}tr[N*2];LL num;
LL a[N];
void renovate (LL *a,LL x,LL y)
{
a[0]=max(a[0],x+y-abs(x)-abs(y));
a[1]=max(a[1],x-y-abs(x)-abs(y));
a[2]=max(a[2],y-x-abs(x)-abs(y));
a[3]=max(a[3],-x-y-abs(x)-abs(y));
}
void update (LL now)
{
LL s1=tr[now].s1,s2=tr[now].s2;
LL x=a[tr[s1].r],y=a[tr[s2].l];
tr[now].sum=tr[s1].sum+tr[s2].sum;
for (LL u=0;u<4;u++) tr[now].a[u]=max(tr[s1].a[u],tr[s2].a[u]);
renovate(tr[now].a,x,y);
}
void bt (LL l,LL r)
{
LL A=++num;
tr[A].l=l;tr[A].r=r;
if (l==r)
{
tr[A].c=a[l];
tr[A].sum=abs(a[l]);
memset(tr[A].a,-63,sizeof(tr[A].a));
return ;
}
LL mid=(l+r)>>1;
tr[A].s1=num+1;bt(l,mid);
tr[A].s2=num+1;bt(mid+1,r);
update(A);
}
void change (LL now,LL x)
{
if (tr[now].l==tr[now].r) {tr[now].c=a[tr[now].l];tr[now].sum=abs(a[tr[now].l]);return ;}
LL mid=(tr[now].l+tr[now].r)>>1;
LL s1=tr[now].s1,s2=tr[now].s2;
if (x<=mid) change(s1,x);
else change(s2,x);
update(now);
}
LL ans[4];
void get (LL now,LL l,LL r)
{
if (tr[now].l==l&&tr[now].r==r)
{
for (LL u=0;u<4;u++) ans[u]=max(ans[u],tr[now].a[u]);
return ;
}
LL s1=tr[now].s1,s2=tr[now].s2;
LL mid=(tr[now].l+tr[now].r)>>1;
if (r<=mid) get(s1,l,r);
else if (l>mid) get(s2,l,r);
else
{
get(s1,l,mid);
get(s2,mid+1,r);
LL x=a[tr[s1].r],y=a[tr[s2].l];
renovate(ans,x,y);
}
}
int main()
{
scanf("%I64d",&n);
for (LL u=1;u<=n;u++) scanf("%I64d",&a[u]);
n--;for (LL u=1;u<=n;u++) a[u]=a[u]-a[u+1];
bt(1,n);
scanf("%I64d",&q);
for (LL u=1;u<=q;u++)
{
LL op,l,r,x;
scanf("%I64d%I64d%I64d%I64d",&op,&l,&r,&x);
if (op==2)//区间修改
{
if (l!=1)
{
a[l-1]-=x;
change(1,l-1);
}
if (r<=n) {a[r]+=x;change(1,r);}
}
else
{
memset(ans,-63,sizeof(ans));
get(1,max(1LL,l-1),min(n,r));
LL lalal=ans[0];
lalal=max(lalal,ans[1]-2*x);
lalal=max(lalal,ans[2]+2*x);
lalal=max(lalal,ans[3]);
/*for (LL j=0;j<4;j++) printf("%I64d ",ans[j]);*/
printf("%I64d\n",tr[1].sum+lalal);
}
/*for (LL i=1;i<=num;i++)
{
printf("l:%I64d r:%I64d c:%I64d sum:%I64d\n",tr[i].l,tr[i].r,tr[i].c,tr[i].sum);
for (LL j=0;j<4;j++) printf("%I64d ",tr[i].a[j]);
printf("\n");
}*/
}
return 0;
}