#include <bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
#define pb push_back
#define eb emplace_back
#define v vector
#define printv(a, x) for (int i = x; i < a.size(); i ++ ) \
cout << a[i] << " \n"[i == (int)a.size() - 1]
#define printvv(a, x) for (int i = x; i < a.size(); i ++ ) \
for (int j = x; j < a[i].size(); j ++ ) \
cout << a[i][j] << " \n"[j == (int)a[i].size() - 1]
#define all(x) (x).begin(), (x).end()
#define readv(a, n, x) for (int i = x; i < n + x; i ++ ) \
cin >> a[i]
#define readvv(a, n, m, x) for (int i = x; i < n + x; i ++ ) \
for (int j = x; j < m + x; j ++ ) \
cin >> a[i][j]
#define gt greater
#define pq priority_queue
#define umap unordered_map
#define uset unordered_set
#define lbound(a, l, r, x) lower_bound(a.begin() + l, a.begin() + r + 1, x) - a.begin()
#define ubound(a, l, r, x) upper_bound(a.begin() + l, a.begin() + r + 1, x) - a.begin()
#define printd(x, d) cout << fixed << setprecision(d) << (x) << '\n'
#define ne_per(a) next_permutation((a).begin(), (a).end())
template <typename T>
void base_dbg (const std::string& key, const T& value) {
std::cerr << key << " = " << value;
}
template <typename... Args>
void dbg_args (const std::string& keys, Args... args) {
size_t pos{ 0 }; ( (base_dbg (keys.substr (pos, keys.find (',', pos) - pos), args),
pos = keys.find (',', pos) + 1), ...);
}
#define dbg(...) { \
std::cerr << ""; \
dbg_args(#__VA_ARGS__, __VA_ARGS__); \
std::cerr << '\n'; \
}
template <typename T>
void base_print (const T& value) {
std::cout << value << ' ';
}
template <typename... Args>
void print_args (Args... args) {
size_t pos{ 0 }; ( (base_print (args) ), ...);
}
#define print(...) { \
std::cout << ""; \
print_args(__VA_ARGS__); \
std::cout << '\n'; \
}
typedef long long i64;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair<int, int> pII;
typedef tuple<int, int, int> pIII;
std::mt19937 rnd (std::chrono::steady_clock().now().time_since_epoch().count() );
struct PII {
int x, y;
bool operator< (const PII &tmp) const {
return x < tmp.x;
}
};
const int N = 2e5 + 10, M = 1e6 + 10, mod = 1e9 + 7,
inf = 0x3f3f3f3f3f3f3f3f, base = 131;
int t, n, m, q, k;
template<class T>
struct MinCostFlow {
struct _Edge {
int to;
T cap;
T cost;
_Edge (int to_, T cap_, T cost_) : to (to_), cap (cap_), cost (cost_) {}
};
int n;
std::vector<_Edge> e;
std::vector<std::vector<int>> g;
std::vector<T> h, dis;
std::vector<int> pre;
bool dijkstra (int s, int t) {
dis.assign (n, std::numeric_limits<T>::max() );
pre.assign (n, -1);
std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int>>, std::greater<std::pair<T, int>>> que;
dis[s] = 0;
que.emplace (0, s);
while (!que.empty() ) {
T d = que.top().first;
int u = que.top().second;
que.pop();
if (dis[u] != d) {
continue;
}
for (int i : g[u]) {
int v = e[i].to;
T cap = e[i].cap;
T cost = e[i].cost;
if (cap > 0 && dis[v] > d + h[u] - h[v] + cost) {
dis[v] = d + h[u] - h[v] + cost;
pre[v] = i;
que.emplace (dis[v], v);
}
}
}
return dis[t] != std::numeric_limits<T>::max();
}
MinCostFlow() {}
MinCostFlow (int n_) {
init (n_);
}
void init (int n_) {
n = n_;
e.clear();
g.assign (n, {});
}
void addEdge (int u, int v, T cap, T cost) {
g[u].push_back (e.size() );
e.emplace_back (v, cap, cost);
g[v].push_back (e.size() );
e.emplace_back (u, 0, -cost);
}
std::pair<T, T> flow (int s, int t) {
T flow = 0;
T cost = 0;
h.assign (n, 0);
while (dijkstra (s, t) ) {
for (int i = 0; i < n; ++i) {
h[i] += dis[i];
}
T aug = std::numeric_limits<int>::max();
for (int i = t; i != s; i = e[pre[i] ^ 1].to) {
aug = std::min (aug, e[pre[i]].cap);
}
for (int i = t; i != s; i = e[pre[i] ^ 1].to) {
e[pre[i]].cap -= aug;
e[pre[i] ^ 1].cap += aug;
}
flow += aug;
cost += aug * h[t];
}
return std::make_pair (flow, cost);
}
T minCost (int s, int t) {
return flow (s, t).second;
}
T maxCost (int s, int t) {
for (int i = 0; i < e[i].size(); i ++ )
e[i].cap *= -1, e[i].cost *= -1;
return -flow (s, t).second;
}
struct Edge {
int from;
int to;
T cap;
T cost;
T flow;
};
std::vector<Edge> edges() {
std::vector<Edge> a;
for (int i = 0; i < e.size(); i += 2) {
Edge x;
x.from = e[i + 1].to;
x.to = e[i].to;
x.cap = e[i].cap + e[i + 1].cap;
x.cost = e[i].cost;
x.flow = e[i + 1].cap;
a.push_back (x);
}
return a;
}
};
void solve() {
int S, T;
cin >> n >> m >> S >> T;
MinCostFlow<int> f (n + 2);
for (int i = 0; i < m; i ++ ) {
int u, v, c, w;
cin >> u >> v >> c >> w;
f.addEdge (u, v, c, w);
}
auto [x, y] = f.flow (S, T);
print (x, y);
}
signed main() {
ios_base::sync_with_stdio (false);
cin.tie (nullptr); cout.tie (nullptr);
t = 1;
while (t -- ) solve();
return 0;
}