參考了這裡 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;}