题目链接:http://codeforces.com/contest/935/problem/F
题意
有一个长度为n的数组A,定义函数F(A)为。
现在有q次操作。
1.l r x代表输出如果在[l, r] 中找一个数加上x之后的F(A)的最大值。
2.l r x代表[l, r] 区间增加x。
题解
我们用d[i]记录a[i + 1] - a[i] ,ans代表当前的F(A)。
对于操作1,有这么几种情况:
1. [l, r] 中存在一个数 a[i] , 使得a[i - 1] < a[i] , a[i + 1] < a[i],这时x加在a[i]上面的收益可以达到 2x。
2. [l, r] 中存在a[i - 1] < a[i] , a[i + 1] > a[i] 或者 a[i - 1] > a[i] ,a[i + 1] < a[i]。我们假设a[i + 1] > a[i],则收益也有两种情况:
① d[i] > x : 收益为 x + a[i + 1] - a[i] - (a[i + 1] - a[i] + x) = 0, 区间长度大于等于2时,一定存在这种情况。
② d[i] < x : 收益为 x + (x - (a[i + 1] - a[i])) - (a[i + 1] - a[i]) = 2 * x - 2 * d[i]。
3. [l, r]中存在 a[i - 1] > a[i] , a[i + 1] > a[i], 这种情况的收益有4种情况。
① d[i] > x && -d[i - 1] > x : 这种情况收益肯定最小,只有可能l = r 的时候存在, 特判一下。
② d[i] < x && -d[i - 1] > x : 这时的收益是 x - (a[i + 1] - a[i]) - (a[i + 1] - a[i]) + (a[i - 1] - a[i] - x) - (a[i - 1] - a[i]) = - 2 * d[i]。
③ d[i] > x && -d[i - 1] < x : 与上同理
④ d[i] < x && -d[i - 1] < x : 2 * x - 2 * d[i] - 2 * -d[i -1]。
至于操作2,区间更新其实只改变了d[l - 1] 和d[r],单独更新一下同时维护ans即可。
综合一下:我们线段树里维护 min(d[i - 1], 0) + min(-d[i], 0) 的最大值。
如果l != r ,那么答案就是max(ans + 2 * query(l, r), 0)。
如果l = r ,答案直接计算即可。
此时全部情况皆被综合了。
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <unordered_set>
#include <cmath>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif
#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MAXN = 2e5 + 5;
const int mod = 1e9 + 7;
int a[MAXN];
ll d[MAXN];
ll tree[MAXN * 4];
ll query (int id, int l, int r, int L, int R) {
if (L <= l && R >= r) {
return tree[id];
}
int mid = (l + r) >> 1;
ll ret = -INFLL;
if (L <= mid) ret = max (ret, query (lson, L, R) );
if (R > mid) ret = max (ret, query (rson, L, R) );
return ret;
}
void update (int id, int l, int r, int x, ll v) {
if (l == r) {
tree[id] = v;
return ;
}
int mid = (l + r) >> 1;
if (x <= mid) update (lson, x, v);
else update (rson, x, v);
tree[id] = max (tree[id << 1], tree[id << 1 | 1]);
}
int main() {
#ifdef LOCAL
freopen ("input.txt", "r", stdin);
#endif
int n;
cin >> n;
ll ans = 0;
for (int i = 1; i <= n; i++) scanf ("%d", &a[i]);
for (int i = 1; i < n; i++) {
d[i] = a[i + 1] - a[i];
ans = (ans + abs(d[i]));
}
for (int i = 1; i <= n; i++) update (1, 1, n, i, min (d[i-1], 0LL) + min (-d[i], 0LL) );
int q;
cin >> q;
debug(ans)
while (q--) {
int op, l, r, x;
scanf ("%d %d %d %d", &op, &l, &r, &x);
if (op == 1) {
if (l == r) printf ("%lld\n", ans + (l == 1 ? 0 : abs (d[l - 1] + x)- abs (d[l - 1]))
+ (l == n ? 0 : -abs (d[l]) + abs (d[l] - x)) );
else {
printf("%lld\n", ans + max(2 * (x + query(1, 1, n, l, r)), 0LL));
debug((x + query(1, 1, n, l, r)))
}
} else {
if(l > 1) {
ans -= abs(d[l - 1]);
d[l - 1] += x;
update(1, 1, n, l - 1, min(d[l - 2], 0LL) + min(-d[l-1], 0LL));
update(1, 1, n, l, min(d[l - 1], 0LL) + min(-d[l], 0LL));
ans += abs(d[l - 1]);
}
if(r < n) {
ans -= abs(d[r]);
d[r] -= x;
update(1, 1, n, r, min(d[r-1], 0LL) + min(-d[r], 0LL));
update(1, 1, n, r + 1, min(d[r], 0LL) + min(-d[r + 1], 0LL));
ans += abs(d[r]);
}
}
}
return 0;
}