#line 1 "template/template.hpp" #include #if __has_include() #include #endif using namespace std; using int64 = long long; const int64 infll = (1LL << 62) - 1; const int inf = (1 << 30) - 1; struct IoSetup { IoSetup() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(10); cerr << fixed << setprecision(10); } } iosetup; template ostream& operator<<(ostream& os, const pair& p) { os << p.first << " " << p.second; return os; } template istream& operator>>(istream& is, pair& p) { is >> p.first >> p.second; return is; } template ostream& operator<<(ostream& os, const vector& v) { for (size_t i = 0; i < v.size(); i++) { os << v[i] << (i + 1 != v.size() ? " " : ""); } return os; } template istream& operator>>(istream& is, vector& v) { for (T& in : v) is >> in; return is; } template bool chmax(T1& a, T2 b) { return a < b && (a = b, true); } template bool chmin(T1& a, T2 b) { return a > b && (a = b, true); } template vector make_v(size_t a) { return vector(a); } template auto make_v(size_t a, Ts... ts) { return vector(ts...))>(a, make_v(ts...)); } template enable_if_t == 0> fill_v(T& t, const V& v) { t = v; } template enable_if_t != 0> fill_v(T& t, const V& v) { for (auto& e : t) fill_v(e, v); } template struct FixPoint : F { explicit FixPoint(F&& f) : F(std::forward(f)) {} template decltype(auto) operator()(Args&&... args) const { return F::operator()(*this, std::forward(args)...); } }; template decltype(auto) MFP(F&& f) { return FixPoint{std::forward(f)}; } #line 2 "graph/flow/dinic-capacity-scaling.hpp" #include #include #include #include #include #include /** * @brief Dinic Capacity Scaling(最大流) * */ template struct DinicCapacityScaling { static_assert(std::is_integral::value, "template parameter flow_t must be integral type"); const flow_t INF; struct edge { int to; flow_t cap; int rev; bool isrev; int idx; }; std::vector > graph; std::vector min_cost, iter; flow_t max_cap; explicit DinicCapacityScaling(int V) : INF(std::numeric_limits::max()), graph(V), max_cap(0) {} void add_edge(int from, int to, flow_t cap, int idx = -1) { max_cap = std::max(max_cap, cap); graph[from].emplace_back( (edge){to, cap, (int)graph[to].size(), false, idx}); graph[to].emplace_back( (edge){from, 0, (int)graph[from].size() - 1, true, idx}); } bool build_augment_path(int s, int t, const flow_t& base) { min_cost.assign(graph.size(), -1); std::queue que; min_cost[s] = 0; que.push(s); while (!que.empty() && min_cost[t] == -1) { int p = que.front(); que.pop(); for (auto& e : graph[p]) { if (e.cap >= base && min_cost[e.to] == -1) { min_cost[e.to] = min_cost[p] + 1; que.push(e.to); } } } return min_cost[t] != -1; } flow_t find_augment_path(int idx, const int t, flow_t base, flow_t flow) { if (idx == t) return flow; flow_t sum = 0; for (int& i = iter[idx]; i < (int)graph[idx].size(); i++) { edge& e = graph[idx][i]; if (e.cap >= base && min_cost[idx] < min_cost[e.to]) { flow_t d = find_augment_path(e.to, t, base, std::min(flow - sum, e.cap)); if (d > 0) { e.cap -= d; graph[e.to][e.rev].cap += d; sum += d; if (flow - sum < base) break; } } } return sum; } flow_t max_flow(int s, int t) { if (max_cap == flow_t(0)) return flow_t(0); flow_t flow = 0; for (int i = 63 - __builtin_clzll(max_cap); i >= 0; i--) { flow_t now = flow_t(1) << i; while (build_augment_path(s, t, now)) { iter.assign(graph.size(), 0); flow += find_augment_path(s, t, now, INF); } } return flow; } void output() { for (int i = 0; i < graph.size(); i++) { for (auto& e : graph[i]) { if (e.isrev) continue; auto& rev_e = graph[e.to][e.rev]; std::cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << std::endl; } } } }; int main() { int N, M, S, T; cin >> N >> M >> S >> T; DinicCapacityScaling< int64 > g(N); for (int i = 0; i < M; i++) { int a, b, c; cin >> a >> b >> c; --a, --b; g.add_edge(a, b, c); } cout << g.max_flow(S - 1, T - 1) << endl; }