2020 计蒜之道 预赛 第一场 D. 染色(困难)(连续区间有额外效益)
题:https://nanti.jisuanke.com/t/48303
题意:有n个位置,每个位置染成黑色有bi效益,染成白色有wi效益,有m个区间[t,l,r,w]当t==1时,[l,r]染成黑色,那么会获得额外效益w,白色同理。求最大效益。
分析:设dp[i]为前 i 位置能获得的最大效益,那么就有基于这个位置染成不同色的三种转移:
- dp[ i ] = dp[ i - 1 ]+max(b[ i ], w[ i ]);(贪心取最大)
- 染成黑色:dp[ i ] = max( dp[ i ], dp[ j ] +(j+1~i连续黑的区间额外效益)+(j+1~i的个体之和的额外效益) );
- 染成白色同理;
对于j+1~i的个体之和的额外效益,我们可以用前缀和来表示:sum[i]-sum[j];
那么后面式子可以转化为dp[ j ] +(j+1~i连续黑的区间额外效益)+sum[i]-sum[j], 所以就取“dp[ j ] +(j+1~i连续黑的区间额外效益)-sum[j]”的最大值;
我们分别建立俩个线段树具体化为俩个更新操作:
- 对每个位置加上dp[ j ]-sum[ j ];
- 对于[ 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; }