#include <bits/stdc++.h>

#define el '\n'
#define fi first
#define sec second
#define pb push_back
#define int long long
#define pii pair<int,int>
#define sz(v) (int)(v).size()
#define all(v) (v).begin(),(v).end()
#define FOR(i, a, b) for(int i = (a), _b = (b); i <= _b; i++)
#define REP(i, a, b) for(int i = (a), _b = (b); i >= _b; i--)

using namespace std;

const int INF = 0x3f3f3f3f3f3f3f3f;
const int MAX_N = 2e5;
const int MAX_M = 3e5;

struct Disjoint_Set_Union{
    int leader[MAX_N + 5], rnk[MAX_N + 5];

    void build(int n){
        FOR(i, 1, n){
            leader[i] = i;
            rnk[i] = 1;
        }
    }

    int get(int u){
        if(u == leader[u]) return u;
        return leader[u] = get(leader[u]);
    }

    void unite(int u, int v){
        int x = get(u), y = get(v);

        if(x == y) return;
        if(rnk[x] < rnk[y]) swap(x, y);

        rnk[x] += rnk[y];
        leader[y] = leader[x];
    }
}dsu;

struct Triple{
    int fi, sec, thr;

    Triple(int _fi = 0, int _sec = 0, int _thr = 0){
        fi = _fi;
        sec = _sec;
        thr = _thr;
    }

    bool operator < (const Triple &other) const{
        return fi < other.fi;
    }
};

vector<Triple> g[MAX_N + 5];
Triple edges[MAX_M + 5];
int dist[MAX_N + 5];
int n, m;

void Input(){
    cin >> n >> m;

    FOR(i, 1, m){
        int u, v, p, w;
        cin >> u >> v >> p >> w;

        g[u].pb({v, p, w});
        g[v].pb({u, p, w});
        edges[i] = {p, u, v};
    }
}

int Kruskal(){
    sort(edges + 1, edges + m + 1);
    dsu.build(n);

    FOR(i, 1, m){
        int u = edges[i].sec, v = edges[i].thr;
        int p = edges[i].fi;

        dsu.unite(u, v);
        if(dsu.get(1) == dsu.get(n)) return p;
    }
}

int dijkstra(int max_p){
    FOR(i, 1, n) dist[i] = INF;
    priority_queue<pii, vector<pii>, greater<pii>> pq;

    pq.push({0, 1});
    dist[1] = 0;

    while(sz(pq)){
        int len = pq.top().fi;
        int u = pq.top().sec;
        pq.pop();

        if(len > dist[u]) continue;

        for(Triple x : g[u]){
            int v = x.fi, p = x.sec, w = x.thr;
            if(p > max_p) continue;
            if(dist[v] > dist[u] + w){
                dist[v] = dist[u] + w;
                pq.push({dist[v], v});
            }
        }
    }

    return dist[n];
}

void Solve(){
    int max_p = Kruskal();
    cout << max_p << " " << dijkstra(max_p);
}

signed main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    Input();
    Solve();

    return 0;
}
