Link.
Description.
给定一个序列 \(a\),找到序列 \(b\) 和 \(c\) 使得:
- \(a_i=b_i+c_i\)
- \(\forall i\in[2,n],b_{i-1}\le b_i,c_{i-1}\ge c_i\)
- 序列的权值定义为最小的 \(\max(b_i,c_i)\)
维护这个序列,支持:
- 区间加
- 查询全局权值
Solution.
最优策略是什么。
首先假设 \(b_1,c_1\) 已经定死了。
每次如果 \(i\in[2,n],a_{i-1}\le a_i\),那就 \(b_i=b_{i-1}+a_i-a_{i-1}\),否则 \(c_i=c_{i-1}+a_i-a_{i-1}\)。
不难证明这样肯定是最优的。
这样最后 \(|b_n-c_n|=|b_1-c_1+\sum_{i=2}^n(a_i-a_{i-1})|\)
设 \(S=\sum_{i=2}^n(a_i-a_{i-1})\),序列最小权值为 \(\max(b_n,c_1)=\max\left(b_1+\sum_{i=2}^n\max(a_i-a_{i-1},0),c_1\right)\)
容易证明,最优指肯定是 \(\left\lceil\frac{a_1+\sum_{i=2}^n\max(a_i-a_{i-1},0)}2\right\rceil\)。
区间加只会影响 \(O(1)\) 个数,暴力改就行了。
Coding.
点击查看代码
//Coded by Kamiyama_Shiki on 2021.11.15 {{{
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=100005;
int n,Q;ll nw[N],a[N],rs,a1;
inline ll get(ll x) {return x>=0?(x+1)/2:-(-x)/2;}
int main()
{
read(n);for(int i=1;i<=n;i++) read(a[i]);
a1=a[1];for(int i=1;i<n;i++) rs+=max(nw[i]=a[i+1]-a[i],0ll);
read(Q),printf("%lld\n",get(a1+rs));for(int l,r,x;Q--;)
{
read(l,r,x);if(l==1) a1+=x;
if(l!=1) rs-=max(nw[l-1],0ll),nw[l-1]+=x,rs+=max(nw[l-1],0ll);
if(r!=n) rs-=max(nw[r],0ll),nw[r]-=x,rs+=max(nw[r],0ll);
printf("%lld\n",get(rs+a1));
}return 0;
}