2020 计蒜之道 预赛 第一场 D. 染色(困难)(连续区间有额外效益)

题:https://nanti.jisuanke.com/t/48303

题意:有n个位置,每个位置染成黑色有bi效益,染成白色有wi效益,有m个区间[t,l,r,w]当t==1时,[l,r]染成黑色,那么会获得额外效益w,白色同理。求最大效益。

分析:设dp[i]为前 i 位置能获得的最大效益,那么就有基于这个位置染成不同色的三种转移:

  1. dp[ i ] = dp[ i - 1 ]+max(b[ i ], w[ i ]);(贪心取最大)
  2. 染成黑色:dp[ i ] = max( dp[ i ], dp[ j ] +(j+1~i连续黑的区间额外效益)+(j+1~i的个体之和的额外效益) );
  3. 染成白色同理;

   对于j+1~i的个体之和的额外效益,我们可以用前缀和来表示:sum[i]-sum[j];

   那么后面式子可以转化为dp[ j ] +(j+1~i连续黑的区间额外效益)+sum[i]-sum[j], 所以就取“dp[ j ] +(j+1~i连续黑的区间额外效益)-sum[j]”的最大值;

   我们分别建立俩个线段树具体化为俩个更新操作:

  1. 对每个位置加上dp[ j ]-sum[ j ];
  2. 对于[ l , i ]区间的额外效益,我们在线段树上的[1,l-1]上区间+额外效益,这样就可以代表,我如果要从[1,l-1]跳转到 i ,那么就可以加上[ l , i ]区间的额外效应。

   由于l-1可能为0,所以我所有位置都往后挪了一位。

#include<bits/stdc++.h>
using namespace std;
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
#define pb push_back
#define MP make_pair

typedef long long ll;
const int M=3e5+5;
const ll INF=1e18;
vector< pair<int,ll> >inb[M],inw[M];
ll b[M],w[M],sumb[M],sumw[M],dp[M];
struct SegTree{
    ll tr[M<<2],lz[M<<2];
    void build(int root,int l,int r){
        tr[root]=lz[root]=0;
        if(l==r)
            return;
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
    }
    void push_up(int root){
        tr[root]=max(tr[root<<1],tr[root<<1|1]);
    }
    void push_down(int root){
        if(lz[root]){
            ll c=lz[root];
            tr[root<<1]+=c,tr[root<<1|1]+=c;
            lz[root<<1]+=c,lz[root<<1|1]+=c;
            lz[root]=0;
        }
    }
    void update(int L,int R,ll c,int root,int l,int r){
        if(L<=l&&r<=R){
            tr[root]+=c;
            lz[root]+=c;
            return ;
        }
        push_down(root);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,c,lson);
        if(R>midd)
            update(L,R,c,rson);
        push_up(root);
    }
    ll query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            return tr[root];
        }
        push_down(root);
        ll res=-INF;
        int midd=(l+r)>>1;
        if(L<=midd)
            res=max(res,query(L,R,lson));
        if(R>midd)
            res=max(res,query(L,R,rson));
        return res;
    }
}segB,segW;
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    n++;
    for(int i=2;i<=n;i++)
        scanf("%lld",&b[i]);
    for(int i=2;i<=n;i++)
        scanf("%lld",&w[i]);
    for(int i=1;i<=n;i++)
        sumb[i]=sumb[i-1]+b[i];
    for(int i=1;i<=n;i++)
        sumw[i]=sumw[i-1]+w[i];
    for(int i=1;i<=m;i++){
        int t,l,r;
        ll val;
        scanf("%d %d %d %lld",&t,&l,&r,&val);
        l++,r++;///按规定右移;
        if(t==1)
            inb[r].pb(MP(l,val));
        else
            inw[r].pb(MP(l,val));
    }
    segB.build(1,1,n),segW.build(1,1,n);
    for(int i=2;i<=n;i++){
        for(auto it:inb[i])
            segB.update(1,it.first-1,it.second,1,1,n);
        for(auto it:inw[i])
            segW.update(1,it.first-1,it.second,1,1,n);
        dp[i]=dp[i-1]+max(b[i],w[i]);
        dp[i]=max(dp[i],segB.query(1,i-1,1,1,n)+sumb[i]);
        dp[i]=max(dp[i],segW.query(1,i-1,1,1,n)+sumw[i]);

        segB.update(i,i,dp[i]-sumb[i],1,1,n);
        segW.update(i,i,dp[i]-sumw[i],1,1,n);
    }
    printf("%lld\n",dp[n]);
    return 0;
}
View Code

 

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