正题
题目链接:https://www.luogu.com.cn/problem/P4126
题目大意
给出nnn个点mmm条边的一张有向图和起点终点。对于每条边求其是否是最小割的可行割/必须割
1≤n≤4000,1≤m≤600001\leq n\leq 4000,1\leq m\leq 600001≤n≤4000,1≤m≤60000
解题思路
一些结论吧,首先是可行割,跑一次最大流,然后如果一条边是可行割需要满足
- 该边满流
- 残量网络上没有x,yx,yx,y之间的环
首先满流是显然的,然后第二个结论的话,如果它们之间有环,那么从yyy顺着环的方向逆流回去的话那么最大流不变但是这条边的流量减少了。
然后必须割的话也是两个条件
- 该边满流
- 残量网络上sss能到xxx,yyy能到ttt
这个我直接搬之前的证明了
证明:在残量网络上sss可以到达xxx且yyy可以到达ttt那么说明若该边不割那么sss就可以通过该边到达ttt。假设在sss到xxx的路上有同样长度的一条道路且割掉后可以使sss到达xxx那么在残量网络上该边的流量必定为0,因为切割掉x−>yx->yx−>y的流量也必定会经过该边所以在残量网络上sss就不可以到达xxx了。所以该假设不成立。
证毕
所以跑完最大流再跑一次tarjantarjantarjan然后按照上面判就好了
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
const int N=4100,M=6e4+10,inf=1e9;
struct node{int to,next,w;
}a[M<<1];
int n,m,s,t,tot,cnt,num,ls[N],id[M];
int dep[N],dfn[N],low[N],col[N];
bool ins[N];
stack<int> st;queue<int> q;
void addl(int x,int y,int w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;return;
}
bool bfs(){while(!q.empty())q.pop();q.push(s);memset(dep,0,sizeof(dep));dep[s]=1;while(!q.empty()){int x=q.front();q.pop();for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(dep[y]||!a[i].w)continue;dep[y]=dep[x]+1;if(y==t)return 1;q.push(y);}}return 0;
}
int dinic(int x,int flow){if(x==t)return flow;int rest=0,k;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(dep[x]+1!=dep[y]||!a[i].w)continue;rest+=(k=dinic(y,min(flow-rest,a[i].w)));a[i].w-=k;a[i^1].w+=k;if(rest==flow)return rest;}if(!rest)dep[x]=0;return rest;
}
void tarjan(int x){dfn[x]=low[x]=++cnt;ins[x]=1;st.push(x);for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(!a[i].w)continue;if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}else if(ins[y])low[x]=min(low[x],dfn[y]);}if(low[x]==dfn[x]){int k;++num;do{k=st.top();st.pop();col[k]=num;ins[k]=0;}while(k!=x);}return;
}
signed main()
{scanf("%d%d%d%d",&n,&m,&s,&t);tot=1;for(int i=1;i<=m;i++){int x,y,w;id[i]=tot+1;scanf("%d%d%d",&x,&y,&w);addl(x,y,w);}while(bfs())dinic(s,inf);for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);for(int i=1;i<=m;i++){int x=a[id[i]^1].to,y=a[id[i]].to;if(a[id[i]].w==0&&col[x]!=col[y])putchar('1');else putchar('0');putchar(' ');if(a[id[i]].w==0&&col[x]==col[s]&&col[y]==col[t])putchar('1');else putchar('0');putchar('\n');}return 0;
}