CF1648D Serious Business题解
题目链接
关键:DP状态的设计
\(dp[i]\) 表示走到\((2,i)\)的最小价值。
转移分类讨论
- 只用一个区间\(i\)从\([li,x]\)选择位置向下拐
\(dp[i]=max_{li\le k \le x}(sum[1][k]+sum[2][x]-sum[2][k-1]+v[i])\) - 使用别的区间
显然转移点小于\(li\),不然用一个区间即可。
\(dp[i]=max_(dp[li-1]+sum[2][x]-sum[2][li-1]-v[i])\)
总结起来(i可能在很多个区间中):
\(dp[x]=max_{li\le x\le ri}(dp[li-1]+sum[2][x]-sum[2][li-1]-v[i],max_{li\le k\le x}(sum[1][k]+sum[2][x]-sum[2][k-1]-v[i]))\)
\(dp[x]=max_{li\le x\le ri}(dp[li-1]-sum[2][li-1]-v[i],max_{li\le k\le x}(sum[1][k]-sum[2][k-1]-v[i]))+sum[2][x]\)
实现:
直接实现显然超时,所以用数据结构优化转移。
前一半显然,可按\(li\)排序后加入线段树维护一下(我感觉拍完序可以直接做,有空来试一试再说,不可以,不好维护x在不在区间)
后一半通过单独维护[l,r]区间可取的最小的vi,以及最大值和答案,因为从小开始加,所以x加入时,加入的li都比x小,线段树查的是大于等与当前位置的最大值,这样x一定在区间中,所以直接加入即可。
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
#define ll long long
const ll inf=1e18;
int n,q;
struct node
{
int l,r,ct;
}qu[N];
ll a[4][N],sum[4][N],dp[N],d1[N<<2],d2[N<<2],lz[N<<2],K2[N<<2];
bool cmp(node x,node y)
{
return x.l<y.l;
}
void pushdown(int i)
{
if(lz[i]==-inf) return ;
d2[i<<1]=max(d2[i<<1],lz[i]-K2[i<<1]);
d2[i<<1|1]=max(d2[i<<1|1],lz[i]-K2[i<<1|1]);
lz[i<<1]=max(lz[i<<1],lz[i]),lz[i<<1|1]=max(lz[i<<1|1],lz[i]);
lz[i]=-inf;
return ;
}
void insert1(int x,int l,int r,int zhi,ll z)
{
if(l==r)
{
d1[x]=max(d1[x],z);
return;
}
int mid=(l+r)>>1;
if(zhi<=mid)insert1(x<<1,l,mid,zhi,z);
else insert1(x<<1|1,mid+1,r,zhi,z);
d1[x]=max(d1[x<<1],d1[x<<1|1]);
}
void insert2(int x,int l,int r,int zhi,ll z,int kk)
{
if(l==r)
{
if(z>d2[x])d2[x]=z,K2[x]=kk;
return;
}
pushdown(x);
int mid=(l+r)>>1;
if(zhi<=mid)insert2(x<<1,l,mid,zhi,z,kk);
else insert2(x<<1|1,mid+1,r,zhi,z,kk);
K2[x]=min(K2[x<<1],K2[x<<1|1]);
d2[x]=max(d2[x<<1],d2[x<<1|1]);
}
ll query1(int x,int l,int r,int zhi)
{
if(r<zhi)return -inf;
if(l>=zhi)return d1[x];
int mid=(l+r)>>1;
return max(query1(x<<1,l,mid,zhi),query1(x<<1|1,mid+1,r,zhi));
}
ll query2(int x,int l,int r,int zhi)
{
if(r<zhi)return -inf;
if(l>=zhi)return d2[x];
pushdown(x);
int mid=(l+r)>>1;
return max(query2(x<<1,l,mid,zhi),query2(x<<1|1,mid+1,r,zhi));
}
void build(int i,int l,int r)
{
d1[i]=d2[i]=lz[i]=-inf,K2[i]=inf;
if(l==r||l>r) return ;
int mid=(l+r)>>1;
build(i<<1,l,mid),build(i<<1|1,mid+1,r);
}
void modify(int i,int l,int r,int suf,ll x){
if(d2[i]==-inf) return ;
if(l>=suf){
lz[i]=max(lz[i],x);
d2[i]=max(d2[i],x-K2[i]);
return ;
}
pushdown(i);
int mid=l+r>>1;
if(mid>=suf) modify(i<<1,l,mid,suf,x);
modify(i<<1|1,mid+1,r,suf,x);
d2[i]=max(d2[i<<1],d2[i<<1|1]);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=3;i++)
for(int j=1;j<=n;j++)
{
scanf("%lld",&a[i][j]);
if(i!=3)sum[i][j]=sum[i][j-1]+a[i][j];
}
for(int i=n;i>=1;i--)sum[3][i]=sum[3][i+1]+a[3][i];
for(int i=1;i<=q;i++)
scanf("%d%d%d",&qu[i].l,&qu[i].r,&qu[i].ct);
sort(qu+1,qu+q+1,cmp);build(1,1,n);
int cnt=1;
for(int i=1;i<=n;i++)
{
modify(1,1,n,i,sum[1][i]-sum[2][i-1]);
while(cnt<=q&&qu[cnt].l<=i)
{
if(qu[cnt].l>1)insert1(1,1,n,qu[cnt].r,dp[qu[cnt].l-1]-sum[2][qu[cnt].l-1]-qu[cnt].ct);
insert2(1,1,n,qu[cnt].r,sum[1][i]-sum[2][i-1]-qu[cnt].ct,qu[cnt].ct);
cnt++;
}
//printf("%d %d\n",query1(1,1,n,i),query2(1,1,n,i));
dp[i]=max(query1(1,1,n,i),query2(1,1,n,i))+sum[2][i];
}
ll ans=-inf;
for(int i=1;i<=n;i++)
ans=max(ans,dp[i]+sum[3][i]);
printf("%lld\n",ans);
return 0;
}