这是题解
感觉没什么好说的,至于为什么要下减上,实质上是差分思想的运用,以将一段连续的东西变成两个单点(如果不是两点,可能不能费用流?)。
最后再巧妙地运用流量守恒原理来表达等式,就可以了。
#include<cstdio>
#include<cstring>
typedef long long ll;
const ll inf=1ll<<62;
const int M=1000005,N=10005;
int q[N*100];
struct graph{
struct edge{
int to,c,next,o;
ll f;
}e[M<<1];
int h[N],xb,le[N],lv[N],n;
ll d[N],mi[N];
bool b[N];
inline void addedge(int u,int v,int w,ll f){
e[++xb]=(edge){v,w,h[u],xb+1,f},h[u]=xb,e[++xb]=(edge){u,-w,h[v],xb-1,0},h[v]=xb;
}
ll mcmf(int S,int T){
register ll ans=0;
register int t,w,u,i,x;mi[S]=inf;
while(1){
t=0,q[w=1]=S;
memset(le+1,0,n<<2),memset(lv+1,0,n<<2);
for(i=1;i<=n;++i)d[i]=inf;d[S]=0;b[S]=1;
while(t<w){
b[u=q[++t]]=0;
for(i=h[u];i;i=e[i].next)
if(e[i].f && d[u]+e[i].c<d[e[i].to]){
d[e[i].to]=d[u]+e[i].c;le[e[i].to]=i,lv[e[i].to]=u;
if(mi[u]>e[i].f)mi[e[i].to]=e[i].f;
else mi[e[i].to]=mi[u];
if(!b[e[i].to])q[++w]=e[i].to,b[e[i].to]=1;
}
}
if(d[T]==inf)return ans;x=mi[T];
for(i=T;i!=S;i=lv[i])
e[le[i]].f-=x,e[e[le[i]].o].f+=x,ans+=1ll*e[le[i]].c*x;
}
}
}g;
int n,m,i,x,y,s,t,c;
int main(){
scanf("%d%d",&n,&m),g.n=n+3;
for(i=1;i<=n;++i){
scanf("%d",&x);
if(x<y)g.addedge(i,n+3,0,y-x);
else g.addedge(n+2,i,0,x-y);
y=x;
g.addedge(i+1,i,0,inf);
}
g.addedge(i,n+3,0,y);
for(i=1;i<=m;++i){
scanf("%d%d%d",&s,&t,&c);
g.addedge(s,t+1,c,inf);
}
return printf("%lld\n",g.mcmf(n+2,n+3)),0;
}