CodeForces 115 E.Linear Kingdom Races(dp+线段树)

202 篇文章 1 订阅
59 篇文章 0 订阅

Description

n n 条道路从左至右编号为1~ n n ,道路均损坏,需要修补才能使用,第i条道路修补的费用为 cost[i] c o s t [ i ] ,现在有 m m 场比赛要举行,其中第i场比赛需要使用 [li,ri] [ l i , r i ] 区间的道路,如果可以成功举办第 i i 场比赛则获利为pi,且由于每场比赛时间不同故不需要考虑两场比赛场地冲突,问最大获利

Input

第一行两个整数 n,m n , m 分别表示道路数量和比赛场数,之后输入 n n 个整数costi表示修补第 i i 条道路的花费,最后m行每行输入三个整数 li,ri,pi l i , r i , p i 表示第 i i 场比赛的场地区间和利润

(1n,m2105,1lirin,1pi109)

Output

输出最大获利

Sample Input

7 4
3
2
3
2
1
2
3
1 2 5
2 3 5
3 5 3
7 7 5

Sample Output

4

Solution

dp[i] d p [ i ] 表示只考虑前 i i 条道路的最大获利,假设要从第j+1条道路一直修到第 i i 条道路,花费为cost(j+1,i)=k=j+1icost[k],利润较之 dp[j] d p [ j ] 多了所有区间右端点不大于 i i 而左端点大于j的比赛利润,假设该段利润为 pay(j+1,i) p a y ( j + 1 , i ) ,那么有转移

dp[i]=max(dp[j]+pay(j+1,i)cost(j+1,i),0j<i) d p [ i ] = m a x ( d p [ j ] + p a y ( j + 1 , i ) − c o s t ( j + 1 , i ) , 0 ≤ j < i )

直接求 pay(j+1,i) p a y ( j + 1 , i ) ​ 比较麻烦,换个角度,场地在 [li,ri] [ l i , r i ] ​ 的比赛会对所有 dp[j]dp[i] d p [ j ] → d p [ i ] ​ 的转移产生影响,只要 j<lirii j < l i ≤ r i ≤ i ​ ,那么把所有比赛按右端点排序,用线段树维护 dp[j]+pay(j+1,i)cost(j+1,i) d p [ j ] + p a y ( j + 1 , i ) − c o s t ( j + 1 , i ) ​ 的最大值,对于当前考虑的 i i ​ ,加入所有右端点不超过 i i ​ 的比赛,假设其左端点为 l l ​ ,那么该场比赛会增加所有 j<l j < l ​ pay(j+1,i) p a y ( j + 1 , i ) ​ ,也即对区间 [0,l1] [ 0 , l − 1 ] ​ 加上其利润 p p ​ ,而对于 cost(j+1,i) c o s t ( j + 1 , i ) ​ 的维护,每次考虑 i i ​ 之前把 cost[i] − c o s t [ i ] ​ 加到区间 [0,i1] [ 0 , i − 1 ] ​ 即可, dp[n] d p [ n ] ​ 即为答案,时间复杂度 O((m+n)logn+mlogm) O ( ( m + n ) l o g n + m l o g m ) ​

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=200005;
struct node
{
    int l,r,p;
    bool operator<(const node &b)const
    {
        return r<b.r;
    }
}a[maxn];
int n,m,cost[maxn];
#define ls (t<<1)
#define rs ((t<<1)|1)
ll dp[maxn],Max[maxn<<2],Lazy[maxn<<2];
void push_up(int t)
{
    Max[t]=max(Max[ls],Max[rs]);
}
void push_down(int t)
{
    if(Lazy[t])
    {
        Lazy[ls]+=Lazy[t];
        Lazy[rs]+=Lazy[t];
        Max[ls]+=Lazy[t];
        Max[rs]+=Lazy[t];
        Lazy[t]=0;
    }
}
void update(int L,int R,int l,int r,int t,ll v)
{
    if(L<=l&&r<=R)
    {
        Lazy[t]+=v;
        Max[t]+=v;
        return ;
    }
    push_down(t);
    int mid=(l+r)/2;
    if(L<=mid)update(L,R,l,mid,ls,v);
    if(R>mid)update(L,R,mid+1,r,rs,v);
    push_up(t);
}
ll query(int L,int R,int l,int r,int t)
{
    if(L<=l&&r<=R)return Max[t];
    push_down(t);
    int mid=(l+r)/2;
    ll ans=0;
    if(L<=mid)ans=max(ans,query(L,R,l,mid,ls));
    if(R>mid)ans=max(ans,query(L,R,mid+1,r,rs));
    push_up(t);
    return ans; 
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&cost[i]);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].p);
    sort(a+1,a+m+1);
    for(int i=1,j=1;i<=n;i++)
    {
        update(0,i-1,0,n,1,-cost[i]);
        while(j<=m&&a[j].r<=i)
        {
            update(0,a[j].l-1,0,n,1,a[j].p);
            j++;
        }
        dp[i]=max(dp[i-1],query(0,i-1,0,n,1));
        update(i,i,0,n,1,dp[i]);
    }
    printf("%I64d\n",dp[n]);
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值