[树状数组] Codeforces 1406D Three Sequences

题目大意

给定一个序列 \(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,q\leq 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_i\geq 0,\Delta c_i\leq 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_i\leq 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\}=\left\lceil \frac{b_n+c_1}{2} \right\rceil=\left\lceil \frac{b_1+\sum_{i=1}^{n-1}\Delta b_i+c_1}{2} \right\rceil=\left\lceil \frac{a_1+\sum_{i=1}^{n-1}\Delta b_i}{2} \right\rceil\)

对于 \(\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\n",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\n",Tree.GetAns());
    }
    return 0;
}
posted @ 2020-10-29 13:39  AE酱  阅读(80)  评论(0编辑  收藏  举报