【题目】
题目描述:
为了绿化乡村,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
输出
3
【样例2】
输入
4 3 3 2 4 1 1 2 4 2 3 5 2 4 6
输出
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
【分析】
这道题应该算是比较裸的差分约束模板题吧
还是用前缀和的思想,即用 d[ i ] 表示前 i 个(包括 i)幢房屋中最少要种的树
那么首先有下面两个限制:
- d[ i - 1 ] ≤ d[ i ],转换成 d[ i ] - d[ i - 1 ] ≥ 0
- d[ i ] - d[ i - 1 ] ≤ k[ i ],转换成 d[ i - 1 ] - d[ i ] ≥ -k[ i ]
假如现在有一条 l 到 r 之间最少有 c 课树的限制,那么:
- d[ r ] - d[ l - 1 ] ≥ c
按照这些限制建完图之后,跑一边 SPFA 就行了,由于是前缀和,最后的答案就是 d[ n ]
备注一点,因为这道题是求最小值,我们要用 SPFA 跑最长路
【代码】
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500005
#define M 2000005
using namespace std;
int Read()
{
int x=0;
char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c))
{
x=(x<<1)+(x<<3)+(c^'0');
c=getchar();
}
return x;
}
int t,d[N],first[M];
int v[M],w[M],next[M];
bool vis[N];
void add(int x,int y,int z)
{
t++;
next[t]=first[x];
first[x]=t;
v[t]=y;
w[t]=z;
}
void spfa(int s)
{
int x,y,i,j;
memset(d,128,sizeof(d));
memset(vis,false,sizeof(vis));
d[s]=0;
vis[s]=true;
queue<int>q;
q.push(s);
while(!q.empty())
{
x=q.front();
q.pop();
vis[x]=false;
for(i=first[x];i;i=next[i])
{
y=v[i];
if(d[y]<d[x]+w[i])
{
d[y]=d[x]+w[i];
if(!vis[y])
{
q.push(y);
vis[y]=true;
}
}
}
}
}
int main()
{
int n,m,i,x,l,r,c;
n=Read();
m=Read();
for(i=1;i<=n;++i)
{
x=Read();
add(i-1,i,0);
add(i,i-1,-x);
}
for(i=1;i<=m;++i)
{
l=Read();
r=Read();
c=Read();
add(l-1,r,c);
}
spfa(0);
printf("%d",d[n]);
return 0;
}