Codeforces Round #670 (Div. 2) D. Three Sequences 题解(差分+思维+构造)

题目链接

题目大意

给你一个长为n的数组a,要你构造一个非严格单调上升的数组b和一个非严格单调下降的数组c,使得\(b_i+c_i=a_i\) 要你使这两个数组b,c中最大的元素最小,还有q次修改(q<=1e5),每次修改使[l,r]上的所有元素加x。在线查询

题目思路

看到这个区间操作,在线查询,就能想到线段树qwq,结果居然是差分

假设现在已经确定了\(b[1]\)\(c[1]\)

假设\(a[2]\)大于\(a[1]\)\(b[2]+c[2]=a[2]\)

显然是想要b数组的每一个元素尽可能小,而c数组是非严格单调上升那么\(c[2]=c[1]\),则\(b[2]=b[2]+(a[2]-a[1])\)

同理可以得出结论

\(a[i]>a[i-1]\)

\(b[i]=b[i-1]+(a[i]-a[i-1])\;\;c[i]=c[i-1]\)

\(a[i]<a[i-1]\)

\(b[i]=b[i-1]\;\;c[i]=c[i-1]+(a[i]-a[i-1])\)

\(ans=\max(b[1],c[n])\)

\(b[1]+c[1]=a[1]\)

\(b[n]=b[1]+s=\sum_{i=2}^{i=n}\max(a[i]-a[i-1],0)\)

上述两式可以推出

\(b[n]+c[1]=a[1]+s\)

则要使得ans最小,则要使得b[n]和c[1]尽可能相近,\(ans=(a[1]+2)/2\)

易错:注意负数/2,c语言中/2是向0靠近

代码

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+5,inf=0x3f3f3f3f;
const double eps=1e-10;
int n,q;
ll a[maxn],b[maxn],res;
ll cal(){
    ll ans=res+b[1];
    if(ans>0){
        return (ans+1)/2;
    }else{
        return ans/2;
    }
}
signed main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        b[i]=a[i]-a[i-1];
        if(i!=1&&b[i]>0){
            res+=b[i];
        }
    }
    printf("%lld\n",cal());
    scanf("%d",&q);
    for(int i=1,l,r,x;i<=q;i++){
        scanf("%d%d%d",&l,&r,&x);
        if(l!=1){
            res=res-max(0ll,b[l])+max(0ll,b[l]+x);
        }
        b[l]+=x;
        if(r!=n){
            res=res-max(0ll,b[r+1])+max(0ll,b[r+1]-x);
        }
        b[r+1]-=x;
        printf("%lld\n",cal());
    }
    return 0;
}

posted @ 2020-09-24 10:45  hunxuewangzi  阅读(104)  评论(0编辑  收藏  举报