【问题描述】
为了绿化乡村,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;
}