//网络流dinic
//最大流=最小割
//基本建模
//建源汇,向每个点分别连所限制的边权,题目所给的边连inf
int cnt=1;
inline void insert(int u,int v,int w)
{
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
e[cnt].f=w;
}
inline void insert(int u,int v,int w)
{
insert1(u,v,w);
insert1(v,w,0);
}
inline int dfs(int now,int f)
{
if(now==t) return f;
for(int i=head[now];i && f;i=e[i].next)
{
if(e[i].f && dep[e[i].to]==dep[now]+1)
{
int d=dfs(e[i].to,min(e[i].f,f));
f-=d;ret+=d;e[i].f-=d;e[i^1].f+=d;
}
}
if(!ret) dep[now]=-1;
return ret;
}
inline bool bfs()
{
memset(dep,0,sizeof(dep));
q.push(s),dep[s]=1;
queue<int> q;
while(!q.empty())
{
int now=q.front();q.pop();
for(int i=head[now];i;i=e[i].next)
if(e[i].f && !dep[e[i].to])
dep[e[i].to]=dep[now]+1,q.push(e[i].to);
}
return dep[t];
}
inline int dinic()
{
int ret=0;
while(bfs()) ret+=dfs(s,1e9+7);
return ret;
}
//二分图
//建立超级源汇,连边权为1,最大流
//最大匹配=最大流
//最大匹配=最小顶点覆盖
//最大点独立集=最小边覆盖
//最大匹配+最小边覆盖=最大点独立集+最小顶点覆盖=|V|
//最大权闭合子图
//正点权和-最小割
//二分图点权最大点独立集
//点权和-最小割
//点限制的网络流
//拆点x0为x1->x2边权为x0的点限制
//费用流
inline int dfs(int now,int f)
{
if(now==t)
{
ans+=f*dis[t];
return f;
}
mark[now]=1;
int ret=0;
for(int i=head[now];i && f;i=e[i].next)
{
if(e[i].f && dis[now]+e[i].cost==dis[e[i].to] && !mark[e[i].to])
{
int d=dfs(e[i].to,min(f,e[i].f));
e[i].f-=d;
e[i^1].f+=d;
ret+=d;
f-=d;
}
}
return ret;
}
inline bool spfa()
{
for(int i=0;i<=n+1;i++) dis[i]=inf;
memset(vis,0,sizeof(vis));
memset(mark,0,sizeof(mark));
q.push(s);vis[s]=1;dis[s]=0;
while(!q.empty())
{
int now=q.front();q.pop();vis[now]=0;
for(int i=head[now];i;i=e[i].next)
{
if(e[i].f && dis[now]+e[i].cost<dis[e[i].to])
{
dis[e[i].to]=dis[now]+e[i].cost;
if(!vis[e[i].to])
{
q.push(e[i].to);
vis[e[i].to]=1;
}
}
}
}
return dis[t]<inf;
}
inline void insert(int u,int v,int f,int w)
{
insert1(u,v,f,w);
insert1(v,u,0,-w);
}
inline int dinic()
{
ans=0;
while(spfa()) dfs(s,inf);
return ans;
}
//建图才是最难滴