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

来源:互联网 发布:java 轮询查询数据库 编辑:程序博客网 时间:2024/06/05 10:30

参考了这里 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|1typedef __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;}