题目链接:https://codeforces.ml/contest/1406/problem/D
题目大意:
给一个序列ai,有一个非递减序列bi和非递减序列ci,要求每一个位置上的bi和ci的和要等于ai,要求bi和ci中的最大值最小,求这个最大值。同时有修改操作,q次修改,给l到r区间的数字加x, 1 < = n < = 1 0 5 , 1 < = q < = 1 0 5 1<=n<=10^5,1<=q<=10^5 1<=n<=105,1<=q<=105
题目思路:
好久没训练了,思维真的跟不上了。。好多并不是很难的思维题完全想不到,得加强训练了。这题一看到就以为是线段树,看了好久都没看出有关的性质,挺糟糕的。。其实有个很容易发现的性质,就是每次bi和ci的变化都跟ai的差分有关。在得到差分后可以发现,如果是正差分,那一定是给bi好,因为如果分一点给ci,那么bi只会更大,变得更烂,反之亦然。所以正差分给b,负差分给c。同时由于bi非递减,ci非递增,所以答案是 m a x ( b n , c 1 ) max(b_n,c_1) max(bn,c1),由于 b 1 + c 1 = a 1 b_1+c_1=a_1 b1+c1=a1所以 c 1 = a 1 − b 1 c_1=a_1-b_1 c1=a1−b1,刚才又得到结论,只有在正差分才给b,那么假设正差分的和为d, b n = b 1 + d b_n=b_1+d bn=b1+d所以答案就是 m a x ( a 1 − b 1 , b 1 + d ) max(a_1-b_1,b_1+d) max(a1−b1,b1+d),很明显是二者相等最小,那么 a 1 − b 1 = b 1 + d a_1-b_1=b_1+d a1−b1=b1+d, a 1 a_1 a1和 d d d是已知的数,可以得到 b 1 = ⌊ a 1 − d 2 ⌋ b_1=\lfloor \frac{a_1-d}{2} \rfloor b1=⌊2a1−d⌋,代入原式,发现我们现在只需要维护 a 1 , d a_1,d a1,d,还有个很舒服的事情就是对l r区间加x的话,仅仅只有 a [ l ] − a [ l − 1 ] a[l]-a[l-1] a[l]−a[l−1]和 a [ r + 1 ] − a [ r ] a[r+1]-a[r] a[r+1]−a[r]这两个差分变化了,所以只用关心这两个地方就行。需要注意的就是l为1和r为n的时候,对应那一端没有差分变化。
以下是代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const int MAXN = 1e6+5;
const int MOD = 998244353;
int n,q,l,r,x;
ll a[MAXN],d[MAXN];
int main(){
while(~scanf("%d",&n)){
rep(i,1,n)scanf("%I64d",&a[i]);
ll sum=0;
rep(i,2,n){
d[i]=a[i]-a[i-1];
if(d[i]>0)sum+=d[i];
}
ll temp=(a[1]-sum)/2;
ll ans=max(temp+sum,a[1]-temp);
printf("%I64d\n",ans);
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&l,&r,&x);
if(l==1)a[1]+=x;
else{
if(d[l]>0)sum-=d[l];
d[l]+=x;
if(d[l]>0)sum+=d[l];
}
if(r<n){
if(d[r+1]>0)sum-=d[r+1];
d[r+1]-=x;
if(d[r+1]>0)sum+=d[r+1];
}
ll temp=(a[1]-sum)/2;
ll ans=max(temp+sum,a[1]-temp);
printf("%I64d\n",ans);
}
}
return 0;
}