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

题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

再接下来m行,每行包括三个整数l_b,u_b,p(1 \leq l_b,u_b \leq n,1 \leq p \leq 10^9)lb?,ub?,p(1≤lb?,ub?≤n,1≤p≤109),表示第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; else15        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==0) return;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}5758void 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

时间: 2024-10-13 16:13:49

题解:CF115E(线段树优化dp)的相关文章

【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp

题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a variant of the game for themselves to play. Being played by clumsy animals weighing nearly a ton, Cow Hopscotch almost always ends in disaster, but this has

BZOJ 1835 基站选址(线段树优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1835 题意:有N个村庄坐落在一条直线上,第 i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村 庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位 置,使得总费用最小. 思路: 另外,程序中的n=n+1,m=

[Poi2010]Monotonicity 2 (线段树优化DP)

题目描述 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k].选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1].求出L的最大值. 输入 第一行两个正整数,分别表示N和K (N, K <= 500,000).第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6).第三行给出K个空格隔开关系符号(>.<或=),第i个表示s[i]. 输出 一个正整数,表示L的

降临(线段树优化dp)

降临 选定点i会有代价\(c_i\),如果一个区间j内的点全被选择,就可以获得回报\(p_j\).点数和区间个数\(<1e5\). 还以为是线段树优化网络流(50万个点200万条边看上去很可做的样子毕竟lbn说过网络流20万万条边完全没问题),没想到是个线段树dp. (虽然这两个线段树完全扯不上关系) 用\(f[i][j]\)表示考虑到第i个点,向左最近的尚未选定的点为j时的最大值.那么,i+1可以选也可以不选.不选i时,\(f[i][j]\rightarrow f[i+1][i+1]\).选i

理想乡题解 (线段树优化dp)

题面 思路概述 首先,不难想到本题可以用动态规划来解,这里就省略是如何想到动态规划的了. 转移方程 f[i]=min(f[j]+1)(max(i-m,0)<=j<i 且j符合士兵限定) 注意要用 max(i-m,0)以防止越界 我们先用两个数组sl,sa分别统计1~i个士兵中有多少个Lencer和Archer 然后在max(i-m,0)中寻找符合条件的j (1).两种士兵相差不超过k. 这个好说abs((sl[i]-sl[j])-(sa[i]-sa[j]))<=k 不要忘了第二种情况!!

Codeforces 833B 线段树优化 dp

Codeforces  833B  The Bakery 题意: n 个数要分成 k 块,每块的价值是其不同数的个数,问价值和最大是多少. tags: dp[i][j]表示前 j 个数分成 i 块的最大权值和,转移: dp[i][j] = max( dp[i-1][k] + val[k+1][j] ) , k是 1~j . 但这个过程其实并不好转移,要利用累加的特点,用线段树进行优化 (感觉我不看题解是想不到的,2333) 大概就是,对于第 i 层,我们假定已经知道了第 i-1 层,也就是求出了

【8.23校内测试】【贪心】【线段树优化DP】

$m$的数据范围看起来非常有问题??仔细多列几个例子可以发现,在$m<=5$的时候,只要找到有两行状态按位$&$起来等于$0$,就是可行方案,如果没有就不行. #include<iostream> #include<cstdio> #include<cstring> using namespace std; int cnt[1<<4+1], n, m; int main ( ) { freopen ( "prob.in",

bzoj 1835 基站选址(线段树优化Dp)

Description 题意:有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di 需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci 如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了 如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi 现在的问题是,选择基站的位置,使得总费用最小. Solution 首先可以想到dp,用dp[i][j]表示前i个村庄建了j个通讯站且第j个建在i处 dp[i][j]=min(dp[k][

hdu45221——小明系列问题——小明序列 线段树优化dp

小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1918    Accepted Submission(s): 583 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找