http://acm.fzu.edu.cn/problem.php?pid=2274
二分差值,求出最小的存在上下界可行流的答案,再跑一次上下界最小流。
这题恶心的地方在于建图从班级流向寝室会TLE,从寝室流向班级就会快很多。
因为只有三层边,dinic里增广次数只有几次,每次dinic复杂度几乎是O(n+m)的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200005,INF=0x3f3f3f3f;
const int mxN=200005,mxM=500005;
int n,m,k;
int du[N];
int ra[N],rb[N],rc[N],rd[N];
int in[N];
int S,T,SS,TT;
int inflow;
struct graph
{
int S,T;
int base[mxN],vec[2*mxM],pre[2*mxM],tot;
int c[2*mxM];
int d[mxN],q[mxN];
bool vis[mxN];
void init()
{
memset(base,0,sizeof(base));
tot=1;
}
void link(int x,int y,int z)
{
vec[++tot]=y; pre[tot]=base[x]; base[x]=tot; c[tot]=z;
vec[++tot]=x; pre[tot]=base[y]; base[y]=tot; c[tot]=0;
}
bool bfs()
{
int head=0,tail=0;
memset(d,-1,sizeof(d));
d[S]=0;
q[++tail]=S;
while(head<tail)
{
head++;
int u=q[head];
for (int now=base[u];now;now=pre[now])
{
int v=vec[now];
if (d[v]==-1&&c[now]>0)
{
d[v]=d[u]+1;
q[++tail]=v;
if (v==T) return 1;
}
}
}
return 0;
}
int dfs(int u,int flow)
{
int r=0;
if (u==T) return flow;
for (int now=base[u];now&&r<flow;now=pre[now])
{
int v=vec[now];
if (c[now]>0&&d[v]==d[u]+1)
{
int x=min(c[now],flow-r);
x=dfs(v,x);
r+=x;
c[now]-=x;
c[now^1]+=x;
}
}
if (!r)d[u]=-2;
return r;
}
int dinic()
{
int ans=0;
while(bfs())
ans+=dfs(S,INF);
return ans;
}
}G;
bool pwork(int dif)
{
G.init();
memset(in,0,sizeof(in));
for (int i=1;i<=k;i++)
G.link(n+rd[i],rc[i],1);
S=0,T=n+m+3;
SS=T-2; TT=T-1;
for (int i=1;i<=n;i++)
{
int l=(du[i]-dif+1)/2;
int r=(du[i]+dif)/2;
if (l<0) l=0;
if (r>du[i]) r=du[i];
if (l>r) return 0;
G.link(i,TT,r-l);
in[i]-=l;
in[TT]+=l;
}
for (int i=1;i<=m;i++)
{
int l=du[n+i]-rb[i];
int r=ra[i];
if (r>du[n+i]) r=du[n+i];
if (l<0) l=0;
G.link(SS,n+i,r-l);
in[SS]-=l;
in[n+i]+=l;
}
inflow=0;
for (int i=1;i<T;i++)
{
if (in[i]>0) G.link(S,i,in[i]),inflow+=in[i];
if (in[i]<0) G.link(i,T,-in[i]);
}
return 1;
}
int maxflow;
bool check(int dif)
{
if (!pwork(dif)) return 0;
G.S=S; G.T=T;
G.link(TT,SS,INF);
int tmp=G.dinic();
return tmp==inflow;
}
int get(int dif)
{
if (!pwork(dif)) return 0;
G.S=S; G.T=T;
G.dinic();
G.link(TT,SS,INF);
return G.dinic();
}
int main()
{
int t; scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(du,0,sizeof(du));
for (int i=1;i<=m;i++)
scanf("%d%d",&ra[i],&rb[i]);
scanf("%d",&k);
for (int i=1;i<=k;i++)
{
scanf("%d%d",&rc[i],&rd[i]);
du[rc[i]]++;
du[n+rd[i]]++;
}
int l=0,r=0;
for (int i=1;i<=n;i++) r=max(r,du[i]);
while(l<r)
{
int mid=(l+r)/2;
if (!check(mid)) l=mid+1;
else r=mid;
}
printf("%d %d\n",r,get(r));
}
return 0;
}