Codeforces Round #670 (Div. 2)D. Three Sequences(非降非升序列组成已知序列,求最小化最大值)

题:http://codeforces.com/contest/1406/problem/D

题意:给定a数组,要求b序列(非降)和c序列(非升)组成a序列(bi+ci=ai),要求输出最小化的最大值max(b1,ci),支持区间加操作

分析:先考虑只求原序列的答案,假设bn=b1+sum(sum>=0,因为是上升序列),由定义:c1=a1-b1;

   而经过观察,a序列中差分为正的就由b来处理,差分为负的就由c来处理,所以sum=Σ(差分为正)。

   那么答案就是max(bn,c1)化简得max(b1+sum,a1-b1);

   只有两种情况:

  • b1+sum>=a1-b1,那么b1要满足b1>=(a1-sum)/2,就选前者;
  • b1+sum<=a1-b1,那么b1要满足b1<=(a1-sum)/2,就选后者;

   然后,因为我们要最小化这个值,那么选择前者时,b1不能大太大,选择后者时b1不能小太小,所以综合b1=(a1-sum)/2。

   接着就是区间加,影响的就只有l ,r+1位置的差分值,简单维护一下更新答案。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=2e5+5;
ll a[M],dis[M];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    ll sum=0;
    for(int i=2;i<=n;i++)
        sum+=max(0ll,a[i]-a[i-1]),dis[i]=a[i]-a[i-1];
    ll b1=(a[1]-sum)/2;
    printf("%lld\n",max(b1+sum,a[1]-sum));
    int m;
    scanf("%d",&m);
    for(int l,r,x,i=1;i<=m;i++){
        scanf("%d %d %d",&l,&r,&x);
        ///
        if(l==1)
            a[1]+=1ll*x;
        else{
            ll las=dis[l];///上次差分值
            sum-=max(0ll,las);
            sum+=max(0ll,las+x);
            dis[l]+=x;
        }
        ///
        if(r!=n){
            ll las=dis[r+1];
            sum-=max(0ll,las);
            sum+=max(0ll,las-x);
            dis[r+1]-=x;
        }
        b1=(a[1]-sum)/2;
        printf("%lld\n",max(b1+sum,a[1]-sum));
    }
    return 0;
}
View Code

 

posted @ 2020-09-13 11:09  starve_to_death  阅读(190)  评论(0编辑  收藏  举报