codeforces 115E Linear Kingdom Races 线段树 + DP 好题

参考了这里 http://blog.sina.com.cn/s/blog_6a6aa7830100x890.html

题意:有N条赛道,每一条初始时都是坏的,修复第i条赛道的费用是cost[i];赛道上会举办m个赛事,每个赛事会用到[L,R]之间的赛道,而且要保证赛事进行必须使得这一段的赛道完好,每项赛事还可以获得一定的钱数。问题要求安排哪些比赛可以使得收益最大。

可以设dp[i]表示到i这个赛道为止能获得最大的利益

有状态转移方程

dp[i]=max(dp[i-1],dp[j]+benefit[j+1][i]-mend[j+1][i]);

注: j+1->i之间有赛道

数据范围200000 暴力的话显然超时,所以可以考虑用某种数据结构优化一下,我用了线段树

做法:

先把m项赛事按右端点递增排个序,这样就可以将以同一个端点结束的赛事一起考虑,去更新前面的DP【】

一项赛事[L,R] 能影响的DP值肯定是在L之前的,即 dp【1~L-1】,要不然比赛场地都不完整,无法获利

还有就是每一次枚举到某段赛道i时,都要对前面所有的DP值 - cost[R],即dp[1~R-1]都减cost[R],  当我们选用所有的以同一个点结尾的赛道时,

dp[L-1]+benefit[L][R]-mend[L][R],获利之前必须先承受L+1~R这段路的维修费用

然后dp[1~L-1]都可以加上L - >R赛道带来的获利,所以给1->L-1这段的DP值加上benefit[L][R],

然后线段树还有一个作用就是查询这个区间的最大值,即更新之后最大的DP值Max[1]

dp[i]=max(dp[i-1],Max[1]);

然后将求得的DP值插入线段树中i位置即可

以下是代码

View Code
#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

#define lson L,R,val,l,m,x<<1

#define rson L,R,val,m+1,r,x<<1|1

typedef __int64 lld;

const int maxn = 200010;

struct seg{

    int l,r;

    lld val;

    bool operator <(const seg &cmp) const{

        return r<cmp.r;

    }

}ss[maxn];

int cost[maxn];

lld dp[maxn],Max[maxn<<2],add[maxn<<2];

lld max(lld a,lld b){

    return a>b?a:b;

}

void pushup(int x){

    Max[x]=max(Max[x<<1],Max[x<<1|1]);

}

void pushdown(int x){

    if(add[x]){

        add[x<<1]+=add[x];

        add[x<<1|1]+=add[x];

        Max[x<<1]+=add[x];

        Max[x<<1|1]+=add[x];

        add[x]=0;

    }

}

void update(int L,int R,lld  val,int l,int r,int x){

    if(L<=l&&r<=R){

        add[x]+=val;

        Max[x]+=val;

        return ;

    }

    pushdown(x);

    int m=(l+r)>>1;

    if(L<=m) update(lson);

    if(R>m) update(rson);

    pushup(x);

}

int main()

{

    int n,m,i,j;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(i=1;i<=n;i++) scanf("%d",&cost[i]);

        for(i=0;i<m;i++) scanf("%d%d%I64d",&ss[i].l,&ss[i].r,&ss[i].val);

        sort(ss,ss+m);

        memset(add,0,sizeof(add));

        memset(Max,0,sizeof(Max));

        dp[0]=0;

        for(i=1,j=0;i<=n;i++)

        {

            update(0,i-1,-cost[i],0,n,1);

            while(ss[j].r==i&&j<m)

            {

                update(0,ss[j].l-1,ss[j].val,0,n,1);

                j++;

            }

            dp[i]=max(dp[i-1],Max[1]);

            update(i,i,dp[i],0,n,1);

        }

        printf("%I64d\n",dp[n]);

    }

    return 0;

}

你可能感兴趣的:(codeforces)