线段树优化DP
是dp[i]=max{dp[j]+w[j+1][i],dp[i-1]},其中1=<i<=n,0=<j<=j-1;
dp[i]表示前i个项目的最大获利,w[j][i]表示项目j到i全部投资的获利。
#include<stdio.h> #include<string.h> #include<stdlib.h> typedef long long ll; int n,m; int a[20010]; struct Item{ int l,r; ll v; }item[20010]; ll dp[20010],w[70010],p[70010]; //用数组p[]标记需要向下压多少,数组w[]存最大值 int cmp(const void * a,const void * b){ struct Item * aa=(struct Item * )a; struct Item * bb=(struct Item * )b; return aa->r-bb->r; } int max(int a,int b){ return a>b?a:b; } void insert(int c,int l,int r,int a,int b,ll val){ int mid; if(a==l && b==r){ w[c]+=val; p[c]+=val; return; } if(p[c]!=0){ w[2*c+1]+=p[c]; p[2*c+1]+=p[c]; w[2*c]+=p[c]; p[2*c]+=p[c]; p[c]=0; } mid=(l+r)>>1; if(a>mid) insert(c*2+1,mid+1,r,a,b,val); else if(b<=mid) insert(c*2,l,mid,a,b,val); else{ insert(c*2,l,mid,a,mid,val); insert(c*2+1,mid+1,r,mid+1,b,val); } w[c]=max(w[2*c+1],w[2*c]); } ll query(int c,int l,int r,int a,int b){ int mid; if(a==l && b==r) return w[c]; if(p[c]!=0){ w[2*c+1]+=p[c]; p[2*c+1]+=p[c]; w[2*c]+=p[c]; p[2*c]+=p[c]; p[c]=0; } mid=(l+r)>>1; if(a>mid) return query(c*2+1,mid+1,r,a,b); else if(b<=mid) return query(c*2,l,mid,a,b); else return max(query(c*2,l,mid,a,mid),query(c*2+1,mid+1,r,mid+1,b)); w[c]=max(w[2*c+1],w[2*c]); } int main(){ int i,j; while(scanf("%d %d",&n,&m)==2){ for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=m;i++) scanf("%d %d %lld",&item[i].l,&item[i].r,&item[i].v); qsort(&item[1],m,sizeof(item[1]),cmp); i=1;j=1; memset(dp,0,sizeof(dp)); memset(w,0,sizeof(w)); memset(p,0,sizeof(p)); for(;i<=n;i++){ insert(1,0,n,0,i-1,-a[i]); while(j<=m && item[j].r<=i){ insert(1,0,n,0,item[j].l-1,item[j].v); j++; } dp[i]=max(dp[i-1],query(1,0,n,0,i-1)); //dp[i]表示前i个项目的最大获利 insert(1,0,n,i,i,dp[i]); } printf("%lld\n",dp[n]); } }