#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;

// struct edge {
//   ll from, to, cost;
//   edge() {}
//   edge(ll from, ll to, ll cost): from(from), to(to), cost(cost) {}
// };

template <class T>
struct Dijkstra {
  struct edge {
    int from, to; T cost;
    edge() {}
    edge(int f, int t, T c) : from(f), to(t), cost(c) {}
  };
 
  int N;
  vector<vector<edge>> G;
  vector<T> dis;
  vector<int> prev;
  Dijkstra() {}
  Dijkstra(int N) : N(N), G(N), dis(N), prev(N, -1) {}
  void add_edge(int f, int t, T c) {
    G[f].emplace_back(f, t, c);
  }
  void shortest_path(int s, T INF) {
    fill(dis.begin(), dis.end(), INF);
    dis[s] = 0;
    using P = pair<T, int>;
    priority_queue<P, vector<P>, greater<P>> que;
    que.emplace(0, s);
    while (!que.empty()) {
      P p = que.top(); que.pop();
      int v = p.second;
      if (dis[v] < p.first) continue;
      for (auto &e : G[v]) {
        if (dis[e.to] > dis[v] + e.cost) {
          dis[e.to] = dis[v] + e.cost;
          prev[e.to] = v;
          que.emplace(dis[e.to], e.to);
        }
      }
    }
  }
  vector<int> get_path(int t) {
    vector<int> path;
    for(; t != -1; t = prev[t]) path.push_back(t);
    reverse(path.begin(), path.end());
    return path;
  }
};

template <typename DATA, typename LAZY>
struct SegmentTree {
  int n;
  DATA e_data;
  vector<LAZY> data;
  SegmentTree() {}
  SegmentTree(int n_, DATA e_data) : e_data(e_data) {
    for (n = 1; n < n_; n <<= 1);
    data.assign(2 * n - 1, e_data);
  }
  DATA merge_element(LAZY lhs, DATA rhs) {
    // 1. RMQ:
    return min(lhs, rhs);
    // 2. RSQ:
    // return lhs + rhs;
  }
  DATA& work_operator_to_element(LAZY& lhs, LAZY rhs) {
    // 1. change lhs to rhs
    return lhs = rhs;
    // 2. add lhs by rhs
    // return lhs += rhs;
  }
  void build(const vector<DATA> array) {
    for (int i = 0;  i < int(array.size()); i++) {
      data[i + n - 1] = array[i];
    }
    for (int i = n - 2; i >= 0; i--) {
      data[i] = merge_element(data[i * 2 + 1], data[i * 2 + 2]);
    }
  }
  void update(int idx, LAZY val, int node = 0, int l = 0, int r = -1) {
    if (r < 0) r = n;
    if (l + 1 == r) {
      work_operator_to_element(data[node], val);
      return;
    }
    int mid = (l + r) / 2;
    if (idx < mid) update(idx, val, node * 2 + 1, l, mid);
    else update(idx, val, node * 2 + 2, mid, r);
    data[node] = merge_element(data[node * 2 + 1], data[node * 2 + 2]);
  }
  DATA query(int a, int b, int node = 0, int l = 0, int r = -1) {
    if (r < 0) r = n;
    if (b <= l || r <= a) return e_data;
    if (a <= l && r <= b) return data[node];
    int mid = (l + r) / 2;
    return merge_element(query(a, b, node * 2 + 1, l, mid), query(a, b, node * 2 + 2, mid, r));
  }
};

const ll INF = 1LL << 50;
ll n, m, s, t;
ll u[100010], v[100010], a[100010], b[100010];
vector<ll> ga[100010], gb[100010];

int main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);
  cout << fixed << setprecision(10);
  
  cin >> n >> m >> s >> t;
  s--, t--;
  for (int i = 0; i < m; i++) {
    cin >> u[i] >> v[i] >> a[i] >> b[i];
    u[i]--, v[i]--;
  }

  Dijkstra<ll> da(n), db(n);
  for (int i = 0; i < m; i++) {
    da.add_edge(u[i], v[i], a[i]);
    da.add_edge(v[i], u[i], a[i]);
    db.add_edge(u[i], v[i], b[i]);
    db.add_edge(v[i], u[i], b[i]);
  }
  da.shortest_path(s, INF);
  db.shortest_path(t, INF);
  vector<ll> v(n);
  for (int i = 0; i < n; i++) {
    v[i] = da.dis[i] + db.dis[i];
  }
  SegmentTree<ll, ll> seg(n, INF);
  seg.build(v);
  for (int i = 0; i < n; i++) {
    cout << (ll)1e15 - seg.query(i, n) << endl;
  }

  return 0;
}

Measured memory_bytes: 30332