[Problem Description]
A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题: 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题。
[Algorithm]
最大流,强连通分量
[Analysis]
先跑最大流是肯定的。然后在残留网络里跑强连通分量。一个原图中的边,如果满流且两点所在的强连通分量不同,则可能出现在最小割中,如果两个强连通分量一个包含s,一个包含t,则一定出现在最小割中
[Pay Attention]
发现自己真是越来越手残了……
[Code]
/**************************************************************
Problem: 1797
User: gaotianyu1350
Language: C++
Result: Accepted
Time:452 ms
Memory:6324 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
const long long MAXN = 5000;
const long long MAXM = 120100;
const long long INF = ((unsigned long long)1<<63) - 1;
long long point[MAXN], nxt[MAXM], f[MAXM], v[MAXM], flow[MAXM], cap[MAXM];
long long lastedge[MAXN], deep[MAXN], num[MAXN], cur[MAXN];
long long tot, n, m, start, end;
bool check[MAXN];
long long dfsTime[MAXN] = {0}, lessTime[MAXN] = {0}, cct[MAXN] = {0}, st[MAXN] = {0};
long long nowTime = 0, cnt = 0, top = 0;
inline long long min(long long a, long long b)
{
return a < b ? a : b;
}
inline long long max(long long a, long long b)
{
return a > b ? a : b;
}
inline void clear()
{
memset(point, -1, sizeof(point));
memset(nxt, -1, sizeof(nxt));
tot = -1;
}
inline void addedge(long long x, long long y, long long theCap)
{
tot++;
nxt[tot] = point[x];
point[x] = tot;
v[tot] = y;
f[tot] =x;
cap[tot] = theCap;
tot++;
nxt[tot] = point[y];
point[y] = tot;
v[tot] = x;
f[tot] = y;
cap[tot] = 0;
}
void bfs(long long s, long long t)
{
queue<int> q;
while (!q.empty()) q.pop();
memset(check, 0, sizeof(check));
memset(deep, 0, sizeof(deep));
check[t] = true;
q.push(t);
while (!q.empty())
{
long long now = q.front();
q.pop();
for (long long temp = point[now]; temp != -1; temp = nxt[temp])
{
long long tt = temp ^ 1;
if (!check[v[temp]] && flow[tt] < cap[tt])
{
check[v[temp]] = true;
deep[v[temp]] = deep[now] + 1;
q.push(v[temp]);
}
}
}
}
inline long long addflow(long long s, long long t)
{
long long ans = INF;
long long now = t;
while (now != s)
{
long long temp = lastedge[now];
ans = min(ans, cap[temp] - flow[temp]);
now = v[temp ^ 1];
}
now = t;
while (now != s)
{
long long temp = lastedge[now];
flow[temp] += ans;
flow[temp ^ 1] -= ans;
now = v[temp ^ 1];
}
return ans;
}
long long isap(long long s, long long t)
{
long long ans = 0;
long long now = s;
bfs(s, t);
memset(num, 0, sizeof(num));
for (long long i = 1; i <= n; i++)
{
num[deep[i]]++;
cur[i] = point[i];
}
while (deep[s] < n)
{
if (now == t)
{
ans += addflow(s, t);
now = s;
}
bool isok = false;
for (long long temp = cur[now]; temp != -1; temp = nxt[temp])
if (deep[now] == deep[v[temp]] + 1 && flow[temp] < cap[temp])
{
isok = true;
lastedge[v[temp]] = temp;
cur[now] = temp;
now = v[temp];
break;
}
if (!isok)
{
long long minn = n - 1;
for (long long temp = point[now]; temp != -1; temp = nxt[temp])
if (flow[temp] < cap[temp])
minn = min(minn, deep[v[temp]]);
if (--num[deep[now]] == 0) break;
num[deep[now] = minn + 1]++;
cur[now] = point[now];
if (s != now) now = v[lastedge[now] ^ 1];
}
}
return ans;
}
void tarjan(long long now)
{
dfsTime[now] = lessTime[now] = ++nowTime;
st[++top] = now;
for (long long temp = point[now]; temp != -1; temp = nxt[temp])
if (flow[temp] < cap[temp])
{
long long tar = v[temp];
if (!dfsTime[tar])
{
tarjan(tar);
lessTime[now] = min(lessTime[now], lessTime[tar]);
}
else if (!cct[tar])
lessTime[now] = min(lessTime[now], dfsTime[tar]);
}
if (dfsTime[now] == lessTime[now])
{
cnt++;
while (1)
{
cct[st[top--]] = cnt;
if (st[top + 1] == now) break;
}
}
}
int main()
{
//freopen("input.txt", "r", "stdin");
clear();
scanf("%lld%lld%lld%lld", &n, &m, &start, &end);
for (long long i = 1; i <= m; i++)
{
long long x, y, z;
scanf("%lld%lld%lld", &x, &y, &z);
addedge(x, y, z);
}
isap(start, end);
for (long long i = 1; i <= n; i++)
if (!dfsTime[i])
tarjan(i);
for (long long i = 1; i <= m; i++)
{
long long now = i * 2 - 2;
if (flow[now] == cap[now] && cct[f[now]] != cct[v[now]])
{
if (cct[f[now]] == cct[start] && cct[v[now]] == cct[end])
printf("1 1\n");
else
printf("1 0\n");
}
else
printf("0 0\n");
}
}