分析

主要考察最小割的性质。我们发现如果一条边是可行边,那么一定要满足以下性质。

  • 满流,没有第二条增广路 。考虑证明,如果没有满流,那么我们完全没必要割去这条边。如果有,那么证明这个路径还可以继续增广,不满足最小割的定义。
    那么如果一条边是必须边。

  • 满流,直接链接 所在集合。这里考虑最小割的定义。

那么我们只需要通过 求出来就行了。数组开的很奔放,不用太在意。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5 + 100,inf = 0x3f3f3f3f;
int read() {
    int x = 0;char ch = getchar();
    while(!isdigit(ch)) {ch = getchar();}
    while(isdigit(ch)) {x = x * 10 + ch - '0';ch = getchar();}
    return x;
}
struct Edge{int to,nxt,from,cap;}e[N<<1];
int head[N],dis[N],cur[N],dfn[N],low[N],scc[N],vis[N],st[N],top,ecnt = 1;
int n,m,S,T;
queue<int> Q;
bool Bfs(int s,int t) {
    memset(dis,0,sizeof(dis));dis[s] = 1;while(Q.size()) Q.pop();
    Q.push(s);
    while(!Q.empty()) {
        int x = Q.front();Q.pop();
        for(int i = head[x];i;i = e[i].nxt) {
            int y = e[i].to;if(!dis[y] && e[i].cap > 0) {
                dis[y] = dis[x] + 1;if(y == t) return true;
                Q.push(y);
            }
        }
    }
    return false;
}
int Dfs(int x,int a,int t) {
    if(x == t || a == 0) return a;
    int flow = 0,f = 0;
    for(int i = cur[x];i;i = e[i].nxt) {
        int y = e[i].to;cur[x] = i;
        if((dis[y] == dis[x] + 1) && ((f = Dfs(y,min(a,e[i].cap),t)) > 0)) {
            e[i].cap -= f;e[i^1].cap += f;flow += f;a -= f;if(!a) break;
        }
    }
    return flow;
}
void add(int x,int y,int cap) {
    e[++ecnt].to = y;e[ecnt].from = x;e[ecnt].cap = cap;e[ecnt].nxt = head[x];head[x] = ecnt;
    e[++ecnt].to = x;e[ecnt].from = 0;e[ecnt].cap = 0  ;e[ecnt].nxt = head[y];head[y] = ecnt;
}
int Scc,Tim;
void tarjan(int x) {
    dfn[x] = low[x] = ++Tim;vis[x] = 1;st[++top] = x;
    for(int i = head[x];i;i = e[i].nxt) {
        int y = e[i].to;if(!e[i].cap) continue;
        if(!dfn[y]) {
            tarjan(y);low[x] = min(low[x],low[y]);
        }
        else if(vis[y]) low[x] = min(low[x],dfn[y]);
    }
    if(dfn[x] == low[x]) {
        Scc++;scc[x] = Scc;
        while(st[top] != x) {
            scc[st[top]] = Scc;vis[st[top]] = 0;top--;
        }
        top--;vis[x] = 0;
    }

}
int main() {
    n = read();m = read();S = read();T = read();
    for(int i = 1;i <= m;i++) {
        int x = read(),y = read(),c = read();add(x,y,c);
    }
    int Maxflow = 0;
    while(Bfs(S,T)) {
        for(int i = 1;i <= n;i++) cur[i] = head[i];Maxflow += Dfs(S,inf,T);
    }
    for(int i = 1;i <= n;i++) {if(!dfn[i]) tarjan(i);}
    for(int i = 2;i <= ecnt;i += 2) {
        if(!e[i].cap) {
            printf("%d %d\n",(scc[e[i].from] != scc[e[i].to]),((scc[e[i].from] == scc[S]) && (scc[e[i].to] == scc[T])) );
        }
        else printf("0 0 \n");
    }
    return 0; 
}