题解:CF115E(线段树优化dp)

 

题目描述

你是一个赛车比赛的组织者,想在线性王国中安排一些比赛。

线性王国有n条连续的从左到右的道路。道路从左到右依次编号为从1到n,因此道路按照升序排列。在这些道路上可能会有几场比赛,每一场比赛都将使用这些道路的某个连续的子序列。而且,如果某场比赛举行了,你将获得一定数额的金钱。没有比赛在时间上重叠,所以每一段道路可以在多个比赛中使用。

不幸的是,所有道路的状况都不佳,需要修理。每条路都有与之相关的维修费用,你需要支付这笔费用来修理道路。只有在某场比赛中需要使用的所有道路都进行了修复,才能进行比赛。你的任务是修复道路并使你的利润最大化。你的利润被定义为你从比赛中获得的总金额减去你花在修理道路上的钱。请注意,您可以决定不修任何道路,并获得利润0。

输出你能获得的最大利润。

输入输出格式

输入格式:

第一行包括两个整数n和m(1 \leq n,m \leq 2\cdot 10^5)(1n,m2105),分别表示道路的数量和比赛的数量。

接下来n行,每行一个整数,表示这条道路修复需要的代价。

再接下来m行,每行包括三个整数l_b,u_b,p(1 \leq l_b,u_b \leq n,1 \leq p \leq 10^9)lb,ub,p(1lb,ubn,1p109),表示第b场比赛需要使用道路l_b,u_blb,ub,你会获得收益p。

输出格式:

输出一个整数,表示你能获得的最大利润。

P.S.请不要使用%lld在C++中读写64位整数。推荐使用cin和cout流(也可以使用%I64d)。

说明

在第一个样例中,最优解是修复1、2、3和7。你将会在第1、2、4三场比赛中获得15的收益。道路修理费用是11,因此你的利润是4

 

解题思路:

 

写出dp方程,发现是区间求最大值,可以用线段树维护

 

 

 1#include<bits/stdc++.h>
2#define N 200005
3#define int long long 
4int c[N],dp[N];
5int now,n,m;
6struct node{
7    int l,r,val;
8}a[N];
9struct tre{
10    int lazy,mx;
11}tree[N*4];
12bool cmp(node a,   node b){
13    if (a.r==b.r) 
14        return a.l<b.l; else
15        return a.r<b.r;
16}
17void read(){
18    std::cin >> n >> m;
19    for (int i=1;i<=n;i++) 
20        std::cin >> c[i];
21    for (int i=1;i<=m;i++)
22        std::cin >> a[i].l >> a[i].r >> a[i].val;
23}
24void Add(int p,int l,int r,int v){
25    tree[p].lazy+=v;
26    tree[p].mx+=v;
27}
28void pushdown(int p,int l,int r,int mid){
29    if (tree[p].lazy==0return;
30    Add(p<<1,l,mid,tree[p].lazy);
31    Add(p<<1|1,mid+1,r,tree[p].lazy);
32    tree[p].lazy=0;
33}
34void modify(int p,int l,int r,int x,int y,int v){
35    if (l>=x&&r<=y){
36        Add(p,l,r,v);
37        return;
38    }
39    int mid=l+r >> 1;
40    if (r<x||l>y) return;
41    pushdown(p,l,r,mid);
42    if (x<=mid) modify(p<<1,l,mid,x,y,v);
43    if (y>mid) modify(p<<1|1,mid+1,r,x,y,v);
44    tree[p].mx=std::max(tree[p<<1].mx,tree[p<<1|1].mx);
45}
46int query(int p,int l,int r,int x,int y){
47    if (l>=x&&r<=y){
48        return tree[p].mx;
49    }
50    int mid=l+r >> 1;
51    int res=0;
52    pushdown(p,l,r,mid);
53    if (x<=mid) res=std::max(res,query(p<<1,l,mid,x,y));
54    if (y>mid) res=std::max(res,query(p<<1|1,mid+1,r,x,y));
55    return res;
56}
57
58void solve(){
59    std::sort(a+1,a+m+1,cmp);
60    now=1;
61    for (int i=1;i<=n+1;i++){
62        while (now<=m&&a[now].r<i){
63            modify(1,0,n+1,0,a[now].l-1,a[now].val);
64            now++;
65        }
66        dp[i]=std::max(dp[i],query(1,0,n+1,0,i-1));
67        modify(1,0,n+1,i,i,dp[i]);
68        modify(1,0,n+1,0,i-1,-c[i]);
69    }
70    std::cout << dp[n+1] << std::endl;
71}
72main(){
73    read();
74    solve();   
75    return 0;
76}

转载于:https://www.cnblogs.com/titititing/p/9575244.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值