#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int _, n, q, s, cnt, num[2][maxn];
const long long inf = ~0ULL >> 1;
vector<pair<int, int>> g[maxn << 2];
struct segment_tree {
  int type, id[maxn << 2];
  segment_tree(int type) : type(type) {}
  void addedge(int u, int v, int w) {
    if (!type) swap(u, v);
    g[u].push_back({v, w});
  }
  void build(int l, int r, int p) {
    if (l == r) return id[p] = l, void();
    id[p] = ++cnt;
    int m = (l + r) >> 1;
    build(l, m, p << 1), build(m + 1, r, p << 1 | 1);
    addedge(id[p], id[p << 1], 0), addedge(id[p], id[p << 1 | 1], 0);
  }
  void link(int l, int r, int p, int L, int R, int u, int w) {
    if (l > R || r < L) return void();
    if (l >= L && r <= R) return addedge(u, id[p], w);
    int m = (l + r) >> 1;
    link(l, m, p << 1, L, R, u, w), link(m + 1, r, p << 1 | 1, L, R, u, w);
  }
};
bool vis[maxn << 2];
long long d[maxn << 2];
priority_queue<pair<long long, int>, vector<pair<long long, int>>,
               greater<pair<long long, int>>>
    que;
void diji(int s) {
  fill(d, d + (maxn << 2), inf);
  while (!que.empty()) que.pop();
  que.push({0, s}), d[s] = 0;
  while (!que.empty()) {
    int u = que.top().second;
    que.pop();
    if (vis[u]) continue;
    vis[u] = 1;
    for (auto pi : g[u]) {
      int v = pi.first, w = pi.second;
      if (d[v] > d[u] + w) {
        d[v] = d[u] + w;
        que.push({d[v], v});
      }
    }
  }
  for (int i = 1; i <= n; i++) printf("%lld ", d[i] == inf ? -1 : d[i]);
}
segment_tree in(1), out(0);
int main() {
  scanf("%d%d%d", &n, &q, &s);
  cnt = n, in.build(1, n, 1), out.build(1, n, 1);
  for (int i = 1; i <= q; i++) {
    int op, u, v, l, r, w;
    scanf("%d", &op);
    if (op == 1) {
      scanf("%d%d%d", &u, &v, &w);
      g[u].push_back({v, w});
    } else if (op == 2) {
      scanf("%d%d%d%d", &u, &l, &r, &w);
      in.link(1, n, 1, l, r, u, w);
    } else {
      scanf("%d%d%d%d", &u, &l, &r, &w);
      out.link(1, n, 1, l, r, u, w);
    }
  }
  diji(s);
  return 0;
}
