开始一直想着把每个点拆分为输和赢两个状态
但还是不管用啊…
一场比赛只能有一个人赢…没必要储存输的情况啊!!
直接源点向比赛连边流量1
比赛向两个人连边流量分别是1,代表只能有一个人赢
然后二分一下就好了
我真是太菜了,哎
#include <bits/stdc++.h>
using namespace std;
#define id(x,y) (x-1)*m+y
const int maxn=2e5+10;
const int inf=1e9;
int n,m,s,t,sumn,dis[maxn],l[maxn],r[maxn];
struct edge{
int to,nxt,flow;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int flow){
d[++cnt]=(edge){v,head[u],flow},head[u]=cnt;
d[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
bool bfs()
{
for(int i=0;i<=t;i++) dis[i]=0;
dis[s]=1;
queue<int>q; q.push( s );
while( !q.empty() )
{
int u=q.front(); q.pop();
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( d[i].flow&&dis[v]==0 )
{
dis[v]=dis[u]+1;
if( v==t ) return true;
q.push( v );
}
}
}
return false;
}
int dinic(int u,int flow)
{
if( u==t ) return flow;
int res=flow;
for(int i=head[u];i&&res;i=d[i].nxt )
{
int v=d[i].to;
if( dis[v]==dis[u]+1&&d[i].flow)
{
int temp=dinic(v,min(res,d[i].flow) );
if( temp==0 ) dis[v]=0;
res-=temp;
d[i].flow-=temp;
d[i^1].flow+=temp;
}
}
return flow-res;
}
int ida[maxn],idb[maxn];
bool isok( int mid )
{
cnt=1;
memset(head,0,sizeof(head));
s=0,t=n+m+1;
int f=n;
for(int i=1;i<=m;i++)
{
++f;
add(s,f,1);
add(f,l[i],1); ida[i]=cnt-1;
add(f,r[i],1); idb[i]=cnt-1;
}
for(int i=1;i<=n;i++) add(i,t,mid);
int ans=0;
while( bfs() ) ans+=dinic(s,inf);
return ans>=m;
}
int main()
{
cin >> n >> m;
for(int i=1;i<=m;i++) cin >> l[i] >> r[i];
int L=1,R=m,mid,ans=0;
while( R>=L )
{
mid = L+R>>1;
if( isok(mid) ) R=mid-1,ans=mid;
else L=mid+1;
}
cout << ans << endl;
isok( ans );
for(int i=1;i<=m;i++)
{
int q=ida[i],w=idb[i];
if( d[q].flow ) cout << 0 << '\n';
else cout << 1 << '\n';
}
}