#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
using pll = pair<ll, ll>;
#define rep(i, n) for(ll i = 0; i < n; i++)
#define Rep(i, m, n) for(ll i = m; i < n; i++)
#define all(vec) vec.begin(), vec.end()
#define tmax(x, y, z) max((x), max((y), (z)))
#define tmin(x, y, z) min((x), min((y), (z)))
#define MINUS(a) memset(a, 0xff, sizeof(a))
#define ZERO(a) memset(a, 0, sizeof(a))
const ll INF = 1LL << 60;
const ll MM = 1000000000; const ll MOD = MM + 7; const ll MMM=9223372036854775807;//2^63 -1
#define ADD(a,b) a = (a + ll(b)) % MOD
#define MUL(a,b) a = (a * ll(b)) % MOD
ll GCD(ll x, ll y){ if(y == 0) return x; else return GCD(y, x % y);}
ll LCM(ll x, ll y){ return x / GCD(x, y) * y;}
template<class T> inline bool chmin(T& a, T b){ if(a > b){ a = b; return true;} return false;}
template<class T> inline bool chmax(T& a, T b){ if(a < b){ a = b; return true;} return false;}
template<typename A, size_t N, typename T> void FILL(A (&array)[N], const T &val){ fill( (T*)array, (T*)(array+N), val );}
// struct edge{ ll from, to, cost; };
struct edge{ ll to, cost; };
// using Graph = vector<vector<ll>>;  // 重み無し
// using Graph = vector<edge>;  // 辺
using Graph = vector<vector<edge>>;  // 重み付き
ll dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
ll ddx[8] = {1, 1, 0, -1, -1, -1, 0, 1}, ddy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
//cout << fixed << setprecision(10);


const ll MAX_V = 100000;  // 制約に従う
Graph G_ene(MAX_V);  // 隣接リスト表現
ll d_ene[MAX_V];
Graph G_snu(MAX_V);  // 隣接リスト表現
ll d_snu[MAX_V];
// 実際の頂点数Vはここで定義する必要なし


void dijkstra_ene(ll s){  // 始点 (0-based)
    priority_queue<pll, vector<pll>, greater<pll>> pq;  // 経路長, 頂点番号
    FILL(d_ene, INF);
    d_ene[s] = 0;
    pq.push(pll(0, s));

    while(!pq.empty()){
        pll p = pq.top(); pq.pop();
        ll v = p.second;  // 確定させる候補の頂点番号
        if(d_ene[v] < p.first) continue;  // より小さいのが後で来るのでスルー
        rep(i, G_ene[v].size()){
            edge e = G_ene[v][i];
            // if(chmin(d_ene[e.to], d_ene[v] + e.cost)) pq.push(pll(d_ene[e.to], e.to));
            if(chmin(d_ene[e.to], p.first + e.cost)) pq.push(pll(d_ene[e.to], e.to));
        }
    }
}


void dijkstra_snu(ll s){  // 始点 (0-based)
    priority_queue<pll, vector<pll>, greater<pll>> pq;  // 経路長, 頂点番号
    FILL(d_snu, INF);
    d_snu[s] = 0;
    pq.push(pll(0, s));

    while(!pq.empty()){
        pll p = pq.top(); pq.pop();
        ll v = p.second;  // 確定させる候補の頂点番号
        if(d_snu[v] < p.first) continue;  // より小さいのが後で来るのでスルー
        rep(i, G_snu[v].size()){
            edge e = G_snu[v][i];
            // if(chmin(d_snu[e.to], d_snu[v] + e.cost)) pq.push(pll(d_snu[e.to], e.to));
            if(chmin(d_snu[e.to], p.first + e.cost)) pq.push(pll(d_snu[e.to], e.to));
        }
    }
}


int main(){
    ll V, m, s, t; cin >> V >> m >> s >> t; s--, t--;  // 0-based
    const ll MONEY = pow(10, 15);
    rep(i, m){
        ll u, v, a, b; cin >> u >> v >> a >> b; u--, v--;  // 0-based
        // 無向グラフなので両方向
        G_ene[u].push_back(edge{v, a});
        G_ene[v].push_back(edge{u, a});
        G_snu[u].push_back(edge{v, b});
        G_snu[v].push_back(edge{u, b});
    }
    dijkstra_ene(s);
    dijkstra_snu(t);

    // secondで両替したときに使用する金額の総和がfirst
    priority_queue<pll, vector<pll>, greater<pll>> pq;
    rep(i, V) pq.push(pll(d_ene[i] + d_snu[i], i));
    pll p = pq.top(); pq.pop();
    rep(i, V){
        while(p.second < i){  // 既に閉鎖されている所で両替しようとしている間
            p = pq.top(); pq.pop();
        }
        cout << MONEY - p.first << endl;
    }
}


Measured memory_bytes: 22772