CF1648D Serious Business题解

题目链接
关键:DP状态的设计
\(dp[i]\) 表示走到\((2,i)\)的最小价值。
转移分类讨论

  1. 只用一个区间\(i\)\([li,x]\)选择位置向下拐
    \(dp[i]=max_{li\le k \le x}(sum[1][k]+sum[2][x]-sum[2][k-1]+v[i])\)
  2. 使用别的区间
    显然转移点小于\(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;
}
posted @ 2024-09-29 15:08  storms11  阅读(3)  评论(0编辑  收藏  举报