#include
using namespace std;
typedef long long dint; #define _l (long long int)
struct edge { int a, b, va, vb; inline void read() { scanf("%d%d%d%d", &a, &b, &va, &vb); } };
struct sptree { int va, vb; sptree() {} sptree(int ao, int bo) { va = ao, vb = bo; } inline dint prd() const { return _l va * vb; } void disp(int x) { printf("(%d,%d)%c", va, vb, x); } }; inline bool operator <(const sptree& a, const sptree& b) { return a. prd() < b. prd() || (a. prd() == b. prd() && a. va < b. va); }
const int maxn = 209; const int maxm = 10009; const int maxv = 60009;
int n, m, ma, mb, r[maxn]; edge e[maxm]; sptree ans;
inline bool cmpEdge(const edge& a, const edge& b) { return a. va * ma + a. vb * mb < b. va * ma + b. vb * mb; }
int getRoot(int x) { register int p, q; for (p = r[x]; p ^ r[p]; p = r[p]); for (; x ^ p; q = r[x], r[x] = p, x = q); return x; }
sptree kruskal(int mav, int mbv) { ma = mav, mb = mbv; sort(e, e + m, cmpEdge); for (int i = 0; i < n; ++ i) r[i] = i; sptree ret(0, 0); for (int i = 0, c = n; i < m && c > 1; ++ i) if (getRoot(e[i]. a) != getRoot(e[i]. b)) { ret. va += e[i]. va; ret. vb += e[i]. vb; r[getRoot(e[i]. a)] = getRoot(e[i]. b); } return ret; }
inline dint mulx(const sptree& a, const sptree& b, const sptree& c) { int xa(b. va - a. va), ya(b. vb - a. vb); int xb(c. va - a. va), yb(c. vb - a. vb); return _l xa * yb - _l xb * ya; }
void dfs(sptree l, sptree r) { sptree md(kruskal(l. vb - r. vb, r. va - l. va)); //l. disp(32), r. disp(10); ans = min(ans, md); if (mulx(l, md, r) != 0) { dfs(l, md); dfs(md, r); } }
int main() { #ifndef ONLINE_JUDGE freopen(“in.txt”, “r”, stdin); #endif
scanf("%d%d", &n, &m);
for (int i = 0; i < m; ++ i)
e[i]. read();
sptree l(kruskal(maxv, 1)), r(kruskal(1, maxv));
ans = min(l, r);
dfs(l, r);
printf("%d %d\n", ans. va, ans. vb);
}