#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN=100010; //点的个数
const int MAXM=400010; //边的个数
const int INF=0x3f3f3f3f;
struct Edge
{
int to,next,cap,flow; //cap代表每条边的容量,flow代表每条边当前的流量大小
}edge[MAXM];
int tol; //代表当前边的条数(编号)
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
//gap:和t的最短距离等于i的结点数量
//dep:每个点的层数(深度)
void init()
{
tol=0;
memset(head,-1,sizeof(head));
}
void addEdge(int u,int v,int w,int rw=0) //加边,如果是单向边的话,传递3个参数(边的起始点,边的终止点,边容量大小),如果是双向边,最后一个参数记录反向边的容量大小
{
edge[tol].to=v;
edge[tol].cap=w;
edge[tol].next=head[u];
edge[tol].flow=0;
head[u]=tol++;
edge[tol].to=u;
edge[tol].cap=rw;
edge[tol].next=head[v];
edge[tol].flow=0;
head[v]=tol++;
//cout<<"tol"<<tol<<endl;
}
int sap(int start,int end,int N) //start代表源点的编号,end代表汇点的编号,N代表总共点的个数,返回值ans代表最大流的流量大小
{
memset(gap,0,sizeof(gap));
memset(dep,0,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u=start;
pre[u]=-1;
gap[0]=N;
int ans=0;
while(dep[start]<N)
{
if(u==end)
{
int Min=INF;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
{
//cout<<edge[i].to<<endl;
edge[i].flow+=Min;
edge[i^1].flow-=Min;
}
u=start;
ans+=Min;
continue;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
{
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag)
{
u=v;
continue;
}
int Min=N;
for(int i=head[u];i!=-1;i=edge[i].next)
{
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
{
Min=dep[edge[i].to];
cur[u]=i;
}
}
gap[dep[u]]--;
if(!gap[dep[u]])
return ans;
dep[u]=Min+1;
gap[dep[u]]++;
if(u!=start)
u=edge[pre[u]^1].to;
}
return ans;
}