CF1406D Three Sequences 题解

Codeforces
Luogu

Description.

给定一个序列 \(a\),找到序列 \(b\)\(c\) 使得:

  1. \(a_i=b_i+c_i\)
  2. \(\forall i\in[2,n],b_{i-1}\le b_i,c_{i-1}\ge c_i\)
  3. 序列的权值定义为最小的 \(\max(b_i,c_i)\)

维护这个序列,支持:

  1. 区间加
  2. 查询全局权值

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;
}
原文地址:https://www.cnblogs.com/pealfrog/p/15558696.html