题目大意
给定一个序列 (a_1,a_2,dots,a_n),要求构造出长度为 (n) 的序列 ({b_n},{c_n}),满足 (a_i=b_i+c_i),并且 ({b_n}) 是不下降序列,({c_n}) 是不上升序列。有 (q) 次操作,每次操作可以把 ([l,r]) 的数增加 (x),求每次操作后最小的 (max{b_i,c_i})。
((n,qleq 10^5))
题解
考虑构造 ({a_n},{b_n},{c_n}) 的差分序列 (Delta a_i=a_{i+1}-a_i,Delta b_i=b_{i+1}-b_i,Delta c_i=c_{i+1}-c_i),那么有 (Delta b_igeq 0,Delta c_ileq 0,Delta a_i=Delta b_i+Delta c_i)。
因为要最小化 (max{b_i,c_i}),当 (Delta a_i>0) 时,令 (Delta b_i=Delta a_i,Delta c_i=0)。当 (Delta a_ileq 0) 时,令 (Delta b_i=0,Delta c_i=Delta a_i)。显然这样是最优的,因为当 (Delta a_i>0) 时,若 (Delta b_i<Delta a_i),则 (Delta c_i>0),不满足;若 (Delta b_i>Delta a_i),则 (Delta c_i<0),此时比 (Delta b_i=Delta a_i) 更劣。
那么假设我们已经确定了 (b_1) 和 (c_1),则 (b_n=b_1+sum_{i=1}^{n-1}Delta b_i)。因为 ({b_n}) 不降, ({c_n}) 不升,所以 (max{b_i,c_i}=max{b_n,c_1}=max{b_1+sum_{i=1}^{n-1}Delta b_i,c_1})。我们肯定是希望 (b_n) 和 (c_1) 越接近越好,因为 (sum_{i=1}^{n-1} Delta b_i) 是固定的,所以我们可以通过将 ({b_n}) 和 ({c_n}) 分别整体平移来使得 (b_n) 和 (c_1) 更接近,所以 (max{b_i,c_i}=leftlceil frac{b_n+c_1}{2} ight ceil=leftlceil frac{b_1+sum_{i=1}^{n-1}Delta b_i+c_1}{2} ight ceil=leftlceil frac{a_1+sum_{i=1}^{n-1}Delta b_i}{2} ight ceil)。
对于 (sum_{i=1}^{n-1}Delta b_i),我们可以通过预处理求出,对于将区间 ([l,r]) 加上 (x),因为我们做了差分,只需要修改左右两个端点对 (Delta b_i) 造成的影响即可,然后还要求每次修改后的 (sum_{i=1}^{n-1}Delta b_i),于是可以使用树状数组来维护,时间复杂度 (O(n log n))。
Code
#include <bits/stdc++.h>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
inline int lowbit(int x){return x&(-x);}
LL a[100010],Delta[100010];
struct BIT{
LL Node[100010];
int N;
void set_Len(int len){N=len;}
void Update(int x,LL Add){for(;x<=N;x+=lowbit(x)) Node[x]+=Add;}
LL PrefixSum(int x){LL Res=0;for(;x;x-=lowbit(x)) Res+=Node[x];return Res;}
LL Query(int L,int R){return PrefixSum(R)-PrefixSum(L-1);}
LL GetAns(){
LL Res=a[1]+PrefixSum(N);
return (Res&1)?((Res>>1)+1):(Res>>1);
}
};
BIT Tree;
int N,M;
int main(){
Read(N);
Tree.set_Len(N-1);
for(RG i=1;i<=N;++i)
Read(a[i]);
for(RG i=1;i<N;++i){
if(a[i+1]-a[i]>0) Tree.Update(i,a[i+1]-a[i]);
Delta[i]=a[i+1]-a[i];
}
printf("%I64d
",Tree.GetAns());
Read(M);
while(M--){
int L,R;LL Add;
Read(L);Read(R);Read(Add);
if(L==1) a[1]+=Add;
if(L>1){
Delta[L-1]+=Add;
Tree.Update(L-1,-Tree.Query(L-1,L-1));
if(Delta[L-1]>0) Tree.Update(L-1,Delta[L-1]);
}
if(R<N){
Delta[R]-=Add;
Tree.Update(R,-Tree.Query(R,R));
if(Delta[R]>0) Tree.Update(R,Delta[R]);
}
printf("%I64d
",Tree.GetAns());
}
return 0;
}