一类新式网络流问题
按时间为键值拆点
链式连边。
考点:流量平衡思想
考点出处:网络流24题最长K重区间覆盖问题
建边:
每一天向下一天连INF-A【i】,0的边
每一次劳工用差分的方式建边INF,c表示乐意效劳
强制要求整条链流量守恒为INF
原理:
由于每天会流出去一些多余的流量所以会强制满流,流是那些劳工边流入
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef int INT;
#define int long long
const int INF=1e17+7;
const int N=2e5;
inline void read(int &x){
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
struct Front_star{
int u,v,w,c,nxt;
}e[N*4];
int cnt=1;
int first[N]={0};
void addedge(int u,int v,int w,int c){
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].c=c;
e[cnt].nxt=first[u];
first[u]=cnt;
}
void add(int u,int v,int w,int c){
// cout<<u<<" "<<v<<'\n';
addedge(u,v,w,c);
addedge(v,u,0,-c);
}
int n,m;
int a[N]={};
int S=0;
int T;
//
int inqueue[N]={};
int dis[N]={};
int pre[N]={};
queue<int> q;
bool bfs(){
for(int i=S;i<=T;i++){
dis[i]=INF;
pre[i]=0;
}
dis[S]=0;
q.push(S);
while(!q.empty()){
int x=q.front();
q.pop();
// cout<<x<<" -"<<'\n';
inqueue[x]=0;
for(int i=first[x];i;i=e[i].nxt){
int v=e[i].v;
// cout<<v<<" -v"<<'\n';
if(dis[x]+e[i].c<dis[v]&&e[i].w){
pre[v]=i;
dis[v]=dis[x]+e[i].c;
if(!inqueue[v]){
inqueue[v]=1;
q.push(v);
}
}
}
}
return dis[T]!=INF;
}
void MCMF(){
int ret=0;
while(bfs()){
// cout<<"dafsQWEHIOEQWHOQEHHJ"<<'\n';
int s=INF+10;
for(int i=pre[T];i;i=pre[e[i^1].v]){
s=min(s,e[i].w);
}
for(int i=pre[T];i;i=pre[e[i^1].v]){
e[i].w-=s;
e[i^1].w+=s;
}
ret+=dis[T]*s;
}
cout<<ret;
}
INT main(){
read(n);
read(m);
for(int i=1;i<=n;i++){
read(a[i]);
}
T=n+2;
for(int i=1;i<=n;i++){
add(i,i+1,INF-a[i],0);
}
for(int i=1;i<=m;i++){
int s,t,c;
read(s);
read(t);
read(c);
add(s,t+1,INF,c);
}
add(S,1,INF,0);
add(n+1,T,INF,0);
MCMF();
return 0;
}