CF115E
CF115E
Linear Kingdom Races
题面翻译
题目描述
你是一个赛车比赛的组织者,想在线性王国中安排一些比赛。
线性王国有
不幸的是,所有道路的状况都不佳,需要修理。每条路都有与之相关的维修费用,你需要支付这笔费用来修理道路。只有在某场比赛中需要使用的所有道路都进行了修复,才能进行比赛。你的任务是修复道路并使你的利润最大化。你的利润被定义为你从比赛中获得的总金额减去你花在修理道路上的钱。请注意,您可以决定不修任何道路,并获得利润
输出你能获得的最大利润。
线段树优化dp模板题
首先我们把这个问题想成染色:
则有:
对于dp[0]的转移是简单的,但是对于dp[1],如果我们使用最朴素的转移,我们就会得到
看着这个式子,我们不难想到线段树优化:
首先开一颗线段树维护dp[1]的转移值,初值为
然后对于每条道路
我们来解释一下这样做的意义是什么:
对于当前节点r,如果线段树取了一个点l,那么就表示当前最后一个染色区间为
然后又因为当前在节点r,也就是说节点r之前的所有节点都已经加入线段树了那么我们在取一个
这样写就符合了我们之前想要的状态转移方程
然后再考虑每个任务:
既然当前节点r与线段树上最优节点l组成了一个区间[l,r],表示最后一个涂色区间为[l,r]
那么对于任务的表示就应该在每一次到达任务右节点R时,将其左节点L在[1,L]打上标记:
也就是表示当前染色区间是[l,r],已经满足R<=r,
接下来只需要满足l<=L就能获得这个区间的贡献
然后这题就做完了
但是还要扣一些细节(详见代码)
#include<bits/stdc++.h> #define ls x<<1 #define rs x<<1|1 #define int long long const int N=2e5+5; const int inf =1e17; using namespace std; int n,m; int dp[N][2],a[N]; void init() { for(int i=0;i<N;i++) { dp[i][0]=dp[i][1]=-inf; } } struct Task{ int l,r,val; }q[N]; struct Tree{ int l,r,tag,val; }t[N<<2]; void pushup(int x) { t[x].val=max(t[ls].val,t[rs].val); return ; } void pushdown(int x) { int tag=t[x].tag; if(tag) { t[ls].tag+=tag,t[rs].tag+=tag; t[ls].val+=tag,t[rs].val+=tag; } t[x].tag=0; return ; } void build(int x,int l,int r) { t[x].l=l,t[x].r=r; if(l==r) { t[x].val=-inf; return ; } int mid=l+r>>1; build(ls,l,mid);build(rs,mid+1,r); pushup(x); } void upd(int x,int ll,int rr,int k) { //cout<<t[x].l<<" "<<t[x].r<<"=="<<ll<<" "<<rr<<"\n"; if(ll>rr)return ; if(ll<=t[x].l&&t[x].r<=rr) { t[x].tag+=k;t[x].val+=k; return ; } pushdown(x); int mid=t[x].l+t[x].r>>1; if(ll<=mid)upd(ls,ll,rr,k); if(mid<rr)upd(rs,ll,rr,k); pushup(x); } void query(int x,int ll,int rr,int &res) { if(ll<=t[x].l&&t[x].r<=rr) { res=max(res,t[x].val); return ; } pushdown(x); int mid=t[x].l+t[x].r>>1; if(ll<=mid)query(ls,ll,rr,res); if(mid<rr)query(rs,ll,rr,res); pushup(x); } bool cmp(Task t1,Task t2) { return t1.r<t2.r; } void work() { cin>>n>>m; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(int i=1;i<=m;i++) { scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].val); } sort(q+1,q+1+m,cmp); int now=1; build(1,1,n+1); upd(1,1,1,inf); //cout<<"upd1"; for(int i=1;i<=n;i++) { upd(1,1,i-1,-a[i-1]); while(q[now].r==i) { upd(1,1,q[now].l,q[now].val); now++; } dp[i][0]=max(dp[i-1][0],dp[i-1][1]); query(1,1,i,dp[i][1]); dp[i][1]-=a[i]; int v=inf+max(dp[i][0],dp[i][1]); upd(1,i+1,i+1,v); } int ans=max(dp[n][0],dp[n][1]); printf("%lld\n",ans); } #undef ls #undef rs #undef int int main() { // freopen("CF115E.in","r",stdin); work(); }