为了绿化乡村,H 村积极响应号召,开始种树了。
H 村里有 n 幢房屋,这些屋子的排列顺序很有特点,在一条直线上。于是方便起见,我们给它们标上 1~n 。树就种在房子前面的空地上。
同时,村民们向村长提出了 m 个意见,每个意见都是按如下格式:希望第 li 个房子到第 ri 个房子的房前至少有 ci 棵树。
因为每个房屋前的空地面积有限,所以每个房屋前最多只能种 ki 棵树。
村长希望在满足村民全部要求的同时,种最少的树以节约资金。请你帮助村长。
为了绿化乡村,H 村积极响应号召,开始种树了。
H 村里有 n 幢房屋,这些屋子的排列顺序很有特点,在一条直线上。于是方便起见,我们给它们标上 1~n 。树就种在房子前面的空地上。
同时,村民们向村长提出了 m 个意见,每个意见都是按如下格式:希望第 li 个房子到第 ri 个房子的房前至少有 ci 棵树。
因为每个房屋前的空地面积有限,所以每个房屋前最多只能种 ki 棵树。
村长希望在满足村民全部要求的同时,种最少的树以节约资金。请你帮助村长。
输入文件输入第 1 行,包含两个整数 n,m 。
第 2 行,有 n 个整数 ki。
第 2~m+1 行,每行三个整数 li,ri,ci 。
输出 1 个整数表示在满足村民全部要求的情况下最少要种的树。村民提的要求是可以全部满足的。
输入
5 3
1 1 1 1 1
1 3 2
2 4 2
4 5 1
输出
3
输入
4 3
3 2 4 1
1 2 4
2 3 5
2 4 6
输出
8
【样例1解释】
如图是满足样例的其中一种方案,最少要种 3 棵树。
【样例2解释】
如图是满足样例的其中两种方案,左图的方案需要种 9 棵树,右图的方案需要种 8 棵树。可以验证,最少需要种 8 棵树。
【数据范围】
对于30%的数据,0
对于50%的数据,0
对于70%的数据,0
对于100%的数据,0
解题报告:
关键词:差分约束系统
开一个s数组记录前缀和。
根据题意我们可以得到3个约束条件:
s[r]-s[l-1]≥c,①
s[i]≥s[i-1],②
s[i]-s[i-1]≤k,③
根据①得s[l-1]-s[r]≤-c,在r和l-1之间连一条权值为-c的边。
根据②得s[i-1]-s[i]≤0,在i和i-1之间连一条权值为0的边。
根据③在i-1和i之间连一条权值为k的边。
50分算法:Bellman-Ford。时间复杂度:O(nm)
70分算法:SPFA。时间复杂度:O(km)
100分算法:观察到最大可能需要连150w条边,因此我们要考虑有些边是否需要连。
我们可以只根据条件①计算,每次更新后O(n)检查是否满足条件②和③,如果不满足就修改,这样只用连50w条边,可以过全部数据。
#include
#include
struct node{
long long u,v,w;
}e[500001];
long long d[500001],k[500000],n,m;
inline long long readint()
{
long long i=0,f=1;
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
for(;ch>='0' && ch<='9';ch=getchar())
i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}
int main()
{
freopen("tree.in","r",stdin);
n=readint();
m=readint();
register long long i,f=1,t;
for(i=1;i<=n;++i) k[i-1]=readint();
for(i=1;i<=m;++i)
{
e[i].v=readint()-1;
e[i].u=readint();
e[i].w=-readint();
}
while(f)
{
f=0;
for(i=1;i<=m;++i)
if(d[e[i].v]>(t=d[e[i].u]+e[i].w)) d[e[i].v]=t,f=1;
for(i=1;i<=n;++i)
if(d[i]-d[i-1]>k[i-1]) d[i]=d[i-1]+k[i-1],f=1;
for(i=n;i;--i)
if(d[i-1]>d[i]) d[i-1]=d[i],f=1;
}
printf("%d\n",d[n]-d[0]);
return 0;
}
var
u,v,w,d,k:array[0..500000]of longint;
n,m,i,f,t,l,r,c,ans:longint;
begin
readln(n,m);
for i:=1 to n do read(k[i-1]);
for i:=1 to m do begin
readln(l,r,c);
v[i]:=l-1;
u[i]:=r;
w[i]:=-c;
end;
f:=1;
while f > 0 do begin
f:=0;
for i:=1 to m do begin
t:=d[u[i]]+w[i];
if d[v[i]]>t then begin
d[v[i]]:=t;
f:=1;
end;
end;
for i:=1 to n do begin
if d[i]-d[i-1]>k[i-1] then begin
d[i]:=d[i-1]+k[i-1];
f:=1;
end;
end;
for i:=n downto 1 do begin
if d[i-1]>d[i] then begin
d[i-1]:=d[i];
f:=1;
end;
end;
end;
ans:=d[n]-d[0];
writeln(ans);
end.