题目大意:
有n块地,初始是荒地。你可以把某些荒地开垦(需要花费相应的价值(a_i)(正整数)),然后这些荒地就可以种田。
现在有m年,每年要在l到r区间内种田,获得p(正整数)的价值(必须保证l~r都已经开荒,否则不能种田)。
问最大收益。
解题思路:
DP。
设F[i][j]表示前i块地,最后有连续的j块地已开荒的最大收益。
则(F[i+1][0]=max{F[i][j]})。不开荒,则中间断了,所以连续的值只有0了。
F[i+1][j+1]=F[i][j]-a[i]+v。开荒,则花费价值,而且可能会有一些年份可以种田了,则加上这些收益(v是加上后能多出来的种田收益)。
于是我们要记录下以每个值作为右端点的种田个数。
答案即为(max{F[n][i]})
发现这是个时空复杂度都是(O(n^2))的东西。
首先第一维可以滚掉。
然后,考虑每个(a[i])都要在整个区间减一遍,而每年种田的价值也会对一段区间有影响。
所以考虑线段树优化。
线段树每个节点记录这个节点下面的儿子的状态的最优值。
然后发现枚举i时,之前的状态都要向右偏移一格,非常麻烦。
倒着建状态就好辣~喵~o( =∩ω∩= )m
C++ Code:
#include<bits/stdc++.h> using namespace std; using LoveLive=long long; const int N=2e5+5; LoveLive d[N*4],tag[N*4],a[N]; int n,m,L,R; LoveLive add; vector<pair<int,LoveLive>>v[N]; inline LoveLive max(LoveLive&a,LoveLive&b){return a>b?a:b;} inline void pd(int&o){ if(tag[o]){ int l=o<<1,r=l|1; d[l]+=tag[o]; d[r]+=tag[o]; tag[l]+=tag[o]; tag[r]+=tag[o]; tag[o]=0; } } void add_1(int l,int r,int o){ if(l==r)d[o]+=add;else{ pd(o); int mid=l+r>>1; if(L<=mid)add_1(l,mid,o<<1);else add_1(mid+1,r,o<<1|1); d[o]=max(d[o<<1],d[o<<1|1]); } } void add_lot(int l,int r,int o){ if(L<=l&&r<=R)d[o]+=add,tag[o]+=add;else{ int mid=l+r>>1; pd(o); if(L<=mid)add_lot(l,mid,o<<1); if(mid<R)add_lot(mid+1,r,o<<1|1); d[o]=max(d[o<<1],d[o<<1|1]); } } int main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n>>m; for(int i=1;i<=n;++i)cin>>a[i]; for(int i=1,l,r;i<=m;++i){ cin>>l>>r>>add; v[r].push_back(make_pair(l,add)); } for(int i=1;i<=n;++i){ L=n-i,add=d[1]; add_1(0,n,1); ++L,R=n,add=-a[i]; add_lot(0,n,1); for(auto it:v[i]){ L=n-it.first+1,R=n,add=it.second; add_lot(0,n,1); } } cout<<d[1]<<endl; return 0; }