网络流模板-网络单纯形
最小费用最大流,但能过 HLPP 板子题,还能处理负环
无上下界
namespace flow{ // }{{{
constexpr int VV = 1200, EE = 120000;
constexpr int V = VV+1, E = EE;
struct Edge{ int to; ll lf, cost; int nxt; } es[E*2+4];
int head[V], fa[V], fe[V], tim, mark[V], ecnt;
ll pi[V];
ll minc, maxf, sumflow, sumcost;
void init(){
minc = maxf = sumflow = sumcost = 0;
tim = ecnt = 2;
std::fill(head, head+V, 0);
std::fill(fe, fe+V, 0);
std::fill(mark, mark+V, 0);
}
void addflow(int s, int t, ll f, ll c){
s++, t++;
es[ecnt] = {t, f, c, head[s]}, head[s] = ecnt++;
es[ecnt] = {s, 0, -c, head[t]}, head[t] = ecnt++;
sumflow += f; sumcost += std::abs(c);
}
void mktree(int x, int fre){
fe[x] = fre;
fa[x] = es[fre^1].to;
mark[x] = 1;
for(int i=head[x]; i; i=es[i].nxt){
if(es[i].lf == 0 || mark[es[i].to] == 1) continue;
mktree(es[i].to, i);
}
}
ll getpi(int x){
if(mark[x] == tim) return pi[x];
mark[x] = tim;
return pi[x] = getpi(fa[x]) + es[fe[x]].cost;
}
ll pushflow(int e){
int rt = es[e].to, lca = es[e^1].to;
++tim;
while(rt){ mark[rt] = tim; rt = fa[rt]; }
while(mark[lca] != tim){ mark[lca] = tim; lca = fa[lca]; }
static std::vector<int> topush;
int dir = -1, todel = e; ll df = es[e].lf;
topush.clear();
topush.push_back(e);
UP(j, 0, 2) for(int i=es[e^!j].to; i!=lca; i=fa[i]){
if(es[fe[i]^j].lf < df){
df = es[fe[i]^j].lf;
todel = fe[i]^j;
dir = j;
}
topush.push_back(fe[i]^j);
}
ll dcst = 0;
if(df) for(int i:topush){
es[i].lf -= df;
es[i^1].lf += df;
dcst += es[i].cost * df;
}
if(todel == e) return dcst;
int laste = e^!dir;
for(int i=es[e^!dir].to; i!=es[todel^!dir].to; ){
int ii = fa[i];
std::swap(laste, fe[i]);
laste ^= 1;
fa[i] = es[fe[i]^1].to;
mark[i] = 0;
i = ii;
}
return dcst;
}
void mcmf(int is, int it){
ll sfl = sumflow+1, scs = sumcost+1;
addflow(it, is, sfl, -scs);
is++, it++;
mktree(it, 0);
int i=2,j=2;
do{
if(es[i].lf && es[i].cost+getpi(es[i^1].to)-getpi(es[i].to)<0){
minc += pushflow(j=i);
}
i=(i==ecnt-1?2:i+1);
} while(i!=j);
maxf = es[ecnt-1].lf;
minc += maxf * scs;
}
} // {}}}
有上下界
namespace flow{ // }{{{
using ll = long long;
constexpr int VV = -0x383494, EE = -0x383494;
constexpr int V = 1+VV+1, E = EE+VV+1;
struct Edge{ int to; ll lf, cost; int nxt; } es[E*2+4];
int head[V], cnt;
ll sumcost = 0, sumflow = 0, minc, maxf, pi[V], ex[V];
int is, it, iv, time, fa[V], fe[V], mark[V];
void init(int v, int s, int t){
is = s+1, it = t+1, iv = v+2;
sd fill(head, head+iv, 0); sd fill(mark, mark+iv, 0); sd fill(fe, fe+iv, 0); sd fill(ex, ex+iv, 0);
time = cnt = 2;
sumcost = sumflow = minc = maxf = 0;
}
void addflow(int s, int t, ll f, ll c, ll minf=0, bool inside = false){
if(!inside) s++, t++;
es[cnt] = (Edge){t, f-minf, c, head[s]}, head[s] = cnt++;
es[cnt] = (Edge){s, 0, -c, head[t]}, head[t] = cnt++;
ex[s] -= minf, ex[t] += minf;
sumflow += f, sumcost += sd abs(c);
minc += minf * c;
}
void mktree(int x, int from_e){
fe[x] = from_e;
fa[x] = es[from_e^1].to;
mark[x] = 1;
for(int i=head[x]; i; i=es[i].nxt){
if(mark[es[i].to] == 1 || es[i].lf == 0) continue;
mktree(es[i].to, i);
}
}
ll getpi(int x){
if(mark[x] == time) return pi[x];
mark[x] = time;
return pi[x] = getpi(fa[x]) - es[fe[x]].cost;
}
ll pushflow(int e){
static std::vector<int> topush;
topush.clear();
int rt = es[e].to, lca = es[e^1].to;
time++;
while(rt){ mark[rt] = time; rt = fa[rt]; }
while(mark[lca] != time){ mark[lca] = time; lca = fa[lca]; }
ll df = es[e].lf;
int todel = e, dir = -1;
UP(j, 0, 2) for(int i=es[e^!j].to; i!=lca; i=fa[i]){
if(es[fe[i]^j].lf < df){
df = es[fe[i]^j].lf;
todel = fe[i];
dir = !j;
}
topush.push_back(fe[i]^j);
}
topush.push_back(e);
ll dcst = 0;
if(df) for(int i:topush){
es[i].lf -= df;
es[i^1].lf += df;
dcst += es[i].cost * df;
}
if(todel == e) return dcst;
int last = e^dir, lastu = es[e^!dir].to;
for(int i=es[last].to; i!=es[todel^1].to; ){
mark[i]=time-1;
int i_ = fa[i];
fa[i] = lastu;
lastu = i;
sd swap(fe[i], last); last ^= 1;
i=i_;
}
return dcst;
}
bool mcmf(){
ll sfl_ = sumflow+1, scs_ = sumcost+1;
int cnt_ = cnt;
UP(i, 0, iv-1){
if(ex[i] > 0){
addflow(iv-1, i, ex[i], -scs_, 0, true);
minc += scs_*ex[i];
} else if(ex[i] < 0){
addflow(i, iv-1, -ex[i], 0, 0, true);
}
}
#if !(NO_FROM_TO)
addflow(it, is, sfl_, -scs_, 0, true);
#endif
sumflow = sfl_-1, sumcost = scs_-1;
mktree(iv-1, 0);
mark[iv-1] = ++time;
fa[iv-1] = 0;
for(int i=2, j=cnt-1; ; i=(i==cnt-1?2:i+1)){
if(es[i].lf && es[i].cost+getpi(es[i].to)-getpi(es[i^1].to)<0){
minc += pushflow(j=i);
} else if(i==j) break;
}
UP(i, cnt_, cnt-2){
if(es[i].lf != 0) return false;
i++;
}
maxf = es[cnt-1].lf;
#if !(NO_FROM_TO)
minc += maxf * scs_;
#endif
return true;
}
} // {}}}