CF708D. Incorrect Flow
题目大意
题解
直接按要求平衡即可,因为源汇可以出入所以要连n->1
贡献根据c<f和c>f讨论,一开始把c设作max(c,f),根据f的变化使c在>=f的情况下尽量靠近原c
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define inf 2000000000
#define ll long long
//#define file
using namespace std;
int a[100001][4],ls[103],g[103],d[1000001],b[101],n,m,i,j,k,l,len=1,x,y,z,c,h,t,st,ed;
ll f[103],ans;
bool bz[103];
void NEW(int x,int y,int f,int w) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;a[len][2]=f;a[len][3]=w;}
void New(int x,int y,int f,int w) {NEW(x,y,f,w),NEW(y,x,0,-w);}
int main()
{
#ifdef file
freopen("CF708D.in","r",stdin);
#endif
scanf("%d%d",&n,&m),st=n+1,ed=n+2;
fo(i,1,m)
{
scanf("%d%d%d%d",&x,&y,&c,&z),b[x]-=z,b[y]+=z;
if (z<=c)
New(y,x,z,1),New(x,y,c-z,1),New(x,y,inf,2);
else
New(y,x,z-c,0),New(y,x,c,1),New(x,y,inf,2),ans+=z-c;
}
fo(i,1,n)
if (b[i]>0) New(st,i,b[i],0);
else New(i,ed,-b[i],0);
New(n,1,inf,0);
while (1)
{
memset(f,127,sizeof(f)),f[st]=0;
h=0,t=1;
d[1]=st,bz[st]=1;
while (h<t)
{
for (i=ls[d[++h]]; i; i=a[i][1])
if (a[i][2] && f[d[h]]+a[i][3]<f[a[i][0]])
{
f[a[i][0]]=f[d[h]]+a[i][3],g[a[i][0]]=i;
if (!bz[a[i][0]])
d[++t]=a[i][0],bz[a[i][0]]=1;
}
bz[d[h]]=0;
}
if (f[ed]>=1152921504606846976ll) break;
l=inf;
for (i=ed; i!=st; i=a[g[i]^1][0]) l=min(l,a[g[i]][2]);
ans+=f[ed]*l;
for (i=ed; i!=st; i=a[g[i]^1][0]) a[g[i]][2]-=l,a[g[i]^1][2]+=l;
}
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}