Codevs 1768 种树

【问题描述】

       为了绿化乡村,H 村积极响应号召,开始种树了。

    H村里有 n 幢房屋,这些屋子的排列顺序很有特点,在一条直线上。于是方便起见,我们给它们标上 1~n 。树就种在房子前面的空地上。

       同时,村民们向村长提出了 m 个意见,每个意见都是按如下格式:希望第 li 个房子到第 ri 个房子的房前至少有 ci 棵树。

       因为每个房屋前的空地面积有限,所以每个房屋前最多只能种 ki 棵树。

       村长希望在满足村民全部要求的同时,种最少的树以节约资金。请你帮助村长。

【输入格式】

       输入文件输入第 1 行,包含两个整数 n,m 。
       第 2 行,有 n 个整数 ki。
       第 2~m+1 行,每行三个整数 li,ri,ci 。

【输出格式】

     输出 1 个整数表示在满足村民全部要求的情况下最少要种的树。村民提的要求是可以全部满足的。

【输入样例1】

5 3
1 1 1 1 1
1 3 2
2 4 2
4 5 1

【输出样例1】

3

【输入样例2】

4 3
3 2 4 1
1 2 4
2 3 5
2 4 6

【输出样例2】

8

备注

【样例1解释】 
如图是满足样例的其中一种方案,最少要种 3 棵树。

【样例2解释】
如图是满足样例的其中两种方案,左图的方案需要种 9 棵树,右图的方案需要种 8 棵树。可以验证,最少需要种 8 棵树。 

【数据范围】
对于30%的数据,0<n≤100,0<m≤100,ki=1; 
对于50%的数据,0<n≤2,000,0<m≤5,000,0<ki≤100; 
对于70%的数据,0<n≤50,000,0<m≤100,000,0<ki≤1,000; 
对于100%的数据,0<n≤500,000,0<m≤500,000,0<ki≤5,000

 

     这道题就是一道很裸的差分约束,对于题目,用tree数组记录前缀和,我们可以得到三个条件:

     1.tree[r]-tree[l-1]>=c

     2.tree[i]-tree[i-1]>=0

     3.tree[i-1]-tree[i]>=-k

   对于上述三个条件,可以按如下方式构图:1.在l-1和r之间连一条权值为c的边;2.在i和i-1之间连一条权值为-k的边;3.在i-1和i之间连一条权值为0的边。这样图就建完了。然后用SPFA跑一个最长路即可

贴代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+10;
const int MAXM=1500001;
const int INF=0x3f3f3f3f;

int cnt,n,tr[MAXN],k;
int dis[MAXN];
int head[MAXN],nxt[MAXM],to[MAXM],w[MAXM],vis[MAXM];
queue<int> q;

int Read()
{
	int i=0,f=1;
	char c;
	for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')
	  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())
	  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

void add(int a,int b,int c)
{
	cnt++;
	nxt[cnt]=head[a];
	head[a]=cnt;
	to[cnt]=b;
	w[cnt]=c;
}

void SPFA(int st)
{
	memset(dis,-INF,sizeof(dis));
	dis[st]=0;
	q.push(st);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();vis[u]=0;
		for(int i=head[u];i;i=nxt[i])
		{
			int v=to[i];
			if(dis[v]<dis[u]+w[i])
			{
				dis[v]=dis[u]+w[i];
				if(!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
		
	}
}

int main()
{
	n=Read(),k=Read();
	tr[0]=0;
	add(0,1,0);
	for(int i=1;i<=n;++i)
	{
		int x;
		x=Read();
		tr[i]=tr[i-1]+x;
		add(i,i+1,0),add(i,i-1,-x);
	}
	for(int i=1;i<=k;++i)
	{
		int x,y,z;
		x=Read(),y=Read(),z=Read();
		add(x-1,y,z);
	}
	SPFA(0);
	printf("%d",dis[n]);
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/81320685
今日推荐