参考了这里 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位置即可
以下是代码
#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; }