zoukankan      html  css  js  c++  java
  • 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
    ",dp[n]);
        return 0;
    }
    View Code
  • 相关阅读:
    HTML基础学习笔记
    CSS-精灵图片的使用(从一张图片中截图指定位置图标)
    侧边栏显示
    HTML <form> action 属性
    2018年寒假小记
    算法提高--接水问题
    基础练习--huffman
    ...
    基础算法
    枚举--最长单词--蓝桥杯
  • 原文地址:https://www.cnblogs.com/starve/p/13661781.html
Copyright © 2011-2022 走看看