[CF115E] Linear Kingdom Races
[CF115E] Linear Kingdom Races
Description
有 \(n\) 个点,\(m\) 次演出 \([L,R]\),可以获得收益 \(val_i\),前提是修复花费代价修复所有点,代价是 \(\sum_{i=l}^{r} cost_i\)。演出区间可以重叠,考虑求最大收益 \(val_i\)。
Solution
我们考虑朴素的 \(dp\),设 \(f_i\) 表示考虑前 \(i\) 个点的最大收益,有 \(f_i=f_j-cost(j+1,i)+val(j+1,i)\)(\(j∈[0,i-1]\))。
复杂度 \(O(n^2)\)。
我们考虑线段树优化,我们维护对于每一个 \(i\),断点 \(j\) 的 \(f_j-cost(j+1,i)+val(j+1,i)\)。
而后我们考虑每次枚举新的 \(i\):
- 将线段树上 \([0,i-1]\) 减去 \(a[i]\),因为强制 \([j+1,i]\) 修好。
- 对于每个右端点为 \(r=i\) 的比赛,将线段树上 \([0,l-1]\) 的值都 \(+v\),因为我们考虑 \(j\) 后面的路都已经修好,可以使得这些比赛价值叠加。
- 更新状态 \(f_i\)。
- 更新线段树上的值。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1)
const int N=5e6+7;
int a[N],n,m;
struct node{
int x,v;
node(int a,int b){x=a,v=b;}
};
vector<node> vec[N];
int f[N];
namespace T{
int maxx[N],tag[N];
void upd(int k,int val){
maxx[k]+=val;
tag[k]+=val;
}
void pushdown(int k){
if(!tag[k]) return;
upd(ls,tag[k]),upd(rs,tag[k]);
tag[k]=0;
}
void pushup(int k){maxx[k]=max(maxx[ls],maxx[rs]);}
void modify(int k,int l,int r,int x,int y,int val){
if(x<=l&&y>=r) return upd(k,val);
pushdown(k);
if(x<=mid) modify(ls,l,mid,x,y,val);
if(y>=mid+1) modify(rs,mid+1,r,x,y,val);
pushup(k);
}
int query(int k,int l,int r,int x,int y){
if(x<=l&&y>=r) return maxx[k];
pushdown(k);
int res=-0x3f3f3f3f;
if(x<=mid) res=max(res,query(ls,l,mid,x,y));
if(y>=mid+1) res=max(res,query(rs,mid+1,r,x,y));
return res;
}
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=m;i++){
int x,y,v;scanf("%lld%lld%lld",&x,&y,&v);
vec[y].push_back(node(x,v));
}
for(int i=1;i<=n;i++){
T::modify(1,0,n,0,i-1,-a[i]);
for(auto [l,v]:vec[i]){
T::modify(1,0,n,0,l-1,v);
}
f[i]=max(f[i-1],T::query(1,0,n,0,i-1));
T::modify(1,0,n,i,i,f[i]);
}
printf("%lld",f[n]);return 0;
}