[AHOI2009]最小割
题意
给定一个带权有向图,对每条边回答:
是否可能出现在最小割中,是否必定出现在最小割中
n<=4000,m<=60000
Solution
根据网络流最大流的性质,可得出结论:
对于最小割中两种边:
可行边:
1.必定满流
2.残量网络中两端不连通
必经边:
1.一定是可行边(有可行边的两条性质)
2.残量网络中两端分别联通S,T
可以先缩点,然后再用并查集判断
code
#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define get getchar()
#define in inline
in int read()
{
int t=0; char ch=get;
while(ch<'0' || ch>'9') ch=get;
while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
return t;
}
const int _=6010;
const int inf=0x3f3f3f3f;
int n,m,S,T,tot=1, h[_];
struct edge{
int to,ne,w,fr;
}e[500010];
in void add(int x,int y,int z)
{
e[++tot].ne=h[x], e[tot].to=y, e[tot].w=z, h[x]=tot, e[tot].fr=x;
e[++tot].ne=h[y], e[tot].to=x, e[tot].w=0, h[y]=tot, e[tot].fr=y;
}
int dis[_],cur[_];
in int dfs(int u,int flow)
{
if(!flow || u==T) return flow;
int used=0,d;
for(re int i=cur[u];i;i=e[i].ne)
{
int v=e[i].to; cur[u]=i;
if(e[i].w && dis[v]==dis[u]+1)
if(d=dfs(v,min(flow-used,e[i].w)))
{
e[i].w-=d, e[i^1].w+=d, used+=d;
if(used==flow) break;
}
}
return used;
}
in int bfs()
{
queue<int> q;
memset(dis,0x3f,sizeof(dis));
dis[S]=0; q.push(S);
while(!q.empty())
{
int u=q.front(); q.pop();
cur[u]=h[u];
for(re int i=h[u],v=e[i].to; i; i=e[i].ne, v=e[i].to)
if(e[i].w && dis[v]==inf) dis[v]=dis[u]+1, q.push(v);
}
return dis[T]!=inf;
}
int ans;
in void dinic()
{ int t; while(bfs())while(t=dfs(S,inf))ans+=t; }
int dfn[_], low[_], vis[_], st[_], top, cnt, num,col[_];
in void tarjan(int u)
{
dfn[u]=low[u]=++cnt;st[++top]=u; vis[u]=1;
for(re int i=h[u];i;i=e[i].ne)
{
int v=e[i].to;
if(!e[i].w) continue;
if(!dfn[v]) {
tarjan(v);
low[u]=min(low[u], low[v]);
}
else if(vis[v]) low[u]=min(low[u], dfn[v]);
}
if(dfn[u]!=low[u]) return;
++num;
while(top)
{
int x=st[top--];
col[x]=num, vis[x]=0;
if(x==u) break;
}
}
int a[_][2];
in void work(int x,int id)
{
queue<int> q; q.push(x); a[x][id]=1;
while(!q.empty())
{
int u=q.front(); q.pop();
for(re int i=h[u];i;i=e[i].ne)
{
int v=e[i].to;
if(!e[i^id].w || a[v][id]) continue;
a[v][id]=1; q.push(v);
}
}
}
int main()
{
n=read(), m=read(), S=read(), T=read();
for(re int i=1;i<=m;i++)
{
int x=read(), y=read(), z=read();
add(x,y,z);
}
dinic();
for(re int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
work(S,0), work(T,1);
for(re int i=2;i<=1+2*m;i+=2)
{
int x=e[i].fr, y=e[i].to;
if(!e[i].w&&col[x]!=col[y]) cout<<"1 ";
else cout<<"0 ";
if(a[x][0]&a[y][1]) cout<<"1\n";
else cout<<0<<endl;
}
}
嗯,就这样了...