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;
}
posted @ 2012-04-25 16:34  Because Of You  Views(601)  Comments(1Edit  收藏  举报