CF115E Linear Kingdom Races

CF115E Linear Kingdom Races

洛谷传送门

题目描述

You are a car race organizer and would like to arrange some races in Linear Kingdom.

Linear Kingdom has nn consecutive roads spanning from left to right. The roads are numbered from 11 to nn from left to right, thus the roads follow in the order of their numbers' increasing. There will be several races that may be held on these roads. Each race will use a consecutive subset of these roads. Also, each race will pay some amount of money to you if this race is held. No races overlap in time, so some roads can be used in several races.

Unfortunately, some of the roads are in a bad condition and they need repair. Each road has repair costs associated with it, you are required to pay this cost to repair the road. A race can only take place if all the roads used in the race are renovated. Your task is to repair such roads (possibly all or none) that will maximize your profit. Your profit is defined as the total money you get from the races that are held minus the total money you spent to repair the roads. Note that you may decide not to repair any road and gain zero profit.

Print the maximum profit you can gain.

输入格式

The first line contains two single-space separated integers, nn and mm ( 1<=n,m<=2·10^{5}1<=n,m<=2⋅105 ), denoting the number of roads and the number of races, respectively.

Then nn lines follow, each line will contain a single non-negative integer not exceeding 10^{9}109 denoting the cost to repair a road. The costs are given in order from road 11 to road nn .

Finally, mm lines follow. Each line is single-space-separated triplets of integers. Each triplet will be given as lbl**b , ubu**b , and pp ( 1<=lb<=ub<=n,1<=p<=10^{9}1<=l**b<=u**b<=n,1<=p<=109 ), which means that the race these three integers describe will use all the roads from lbl**b to ubu**b , inclusive, and if it's held you get pp .

输出格式

Print a single integer denoting the maximum possible profit you can gain.

Please, do not use the %lld specificator to read or write 64-bit integers in C++. It is recommended to use cin, cout stream (also you may use %I64d specificator).

题意翻译

题目描述

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

线性王国有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)l**b,u**b,p(1≤l**b,u**bn,1≤p≤109),表示第b场比赛需要使用道路l_b,u_bl**b,u**b,你会获得收益p。

输出格式:

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

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

说明

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


题解:

感谢翻译官的翔实处理。

最优化问题,一开始以为是贪心。贪心策略是对于每一个比赛来讲,如果它的收益小于消费,那么肯定是很不划算的。但是觉得这道题不应该这么简单。于是发现:对于某段区间,可能被多次覆盖,但是只拿一次的花费。于是贪心变得不可行,开始思考DP。

沿袭刚刚的思路,考虑设置\(DP\)\(dp[i]\)表示前i场比赛的最大价值。(加排序)但是发现,由于并集缘故,不能转移。所以设置\(dp[i]\)表示前i个道路的最大价值。

转移应该是很好想的。

对于每一个新的i,有选、不选两种转移。不选的话就是\(dp[i]=dp[i-1]\),选的话就是\(dp[i]=\max(dp[j]+w[j])\),其中\(w[j]\)是拓展当前道路对答案的贡献。

需要拓展哪些道路呢?或者说,哪些道路是对当前答案有贡献的呢?当然是那些右端点正好在i点的比赛们。于是我们采用挂链(vector挂链)方式把每个右端点对应的所有左端点挂上,然后就可以转移了。

贡献是什么呢?根据题意,贡献就是比赛的盈利减去这个区间的花费。

我们发现,转移的时候要频繁修改区间,那么为了保证时间复杂度,我们采用线段树来优化这个东西。维护一棵线段树,维护\(dp[j]+w[j]\)。维护过程如下:

首先,对于每个i,先对区间\([0,i-1]\)统一减去\(v[i]\)

然后对于每个可转移的比赛区间\([l,r]\),对\([0,l-1]\)统一加上p。

最后查询的就是\([0,i-1]\)的区间最大值。更新状态,并把新状态赋给新线段树。

所以代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#define int long long
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
const int maxn=2*1e5+10;
const int INF=1e9;
struct add
{
	int l,k;
	add(int p,int q)
	{
		l=p,k=q;
	}
};
int n,m;
int v[maxn];
vector<add> vec[maxn];
int tree[maxn<<2],lazy[maxn<<2];
int dp[maxn];
void pushup(int pos)
{
	tree[pos]=max(tree[lson],tree[rson]);
}
void mark(int pos,int l,int r,int k)
{
	tree[pos]+=k;
	lazy[pos]+=k;
}
void pushdown(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	mark(lson,l,mid,lazy[pos]);
	mark(rson,mid+1,r,lazy[pos]);
	lazy[pos]=0;
}
void update(int pos,int l,int r,int x,int y,int k)
{
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
	{
		mark(pos,l,r,k);
		return;
	}
	pushdown(pos,l,r);
	if(x<=mid)
		update(lson,l,mid,x,y,k);
	if(y>mid)
		update(rson,mid+1,r,x,y,k);
	pushup(pos);
}
int query(int pos,int l,int r,int x,int y)
{
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
		return tree[pos];
	pushdown(pos,l,r);
	int ret=-INF;
	if(x<=mid)
		ret=max(ret,query(lson,l,mid,x,y));
	if(y>mid)
		ret=max(ret,query(rson,mid+1,r,x,y));
	return ret;
}
signed main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%lld",&v[i]);
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		scanf("%lld%lld%lld",&x,&y,&z);
		vec[y].push_back(add(x,z));
	}
	for(int i=1;i<=n;i++)
	{
		update(1,0,n,0,i-1,-v[i]);
		for(int j=0;j<vec[i].size();j++)
		{
			int ll=vec[i][j].l,kk=vec[i][j].k;
			update(1,0,n,0,ll-1,kk);
		}
		dp[i]=max(query(1,0,n,0,i-1),dp[i-1]);
		update(1,0,n,i,i,dp[i]);
	}
	printf("%lld",dp[n]);
	return 0;
}
posted @ 2020-10-23 18:26  Seaway-Fu  阅读(938)  评论(0编辑  收藏  举报