#include <bits/stdc++.h>
using namespace std;
template <typename T1, typename T2>
inline void chkmin(T1& x, T2 y) {
  if (x > y) x = y;
}
template <typename T1, typename T2>
inline void chkmax(T1& x, T2 y) {
  if (x < y) x = y;
}
const int MAXN = 1e5 + 1;
const long long INF = 1e18;
int pos[MAXN];
bool used[MAXN];
struct edge {
  int l, r, c, num;
  edge(int _l, int _r, int _c, int _num) { l = _l, r = _r, c = _c, num = _num; }
};
struct node {
  long long dist, pushed;
  bool used, relaxed;
  vector<edge> edges;
  int from;
  node() {
    dist = pushed = INF;
    used = relaxed = false;
    from = -1;
  }
};
vector<node> tree;
void push(int v) {
  int lc = v << 1, rc = lc + 1;
  long long val = tree[v].pushed;
  if (val == INF) return;
  chkmin(tree[lc].pushed, val), chkmin(tree[lc].dist, val);
  chkmin(tree[rc].pushed, val), chkmin(tree[rc].dist, val);
}
void upd(int v) {
  int ls = v << 1, rs = ls + 1;
  tree[v].dist = tree[v].pushed, tree[v].from = -1;
  if (tree[ls].used && tree[rs].used) {
    tree[v].used = true;
    return;
  }
  if (!tree[ls].used && tree[v].dist > tree[ls].dist)
    tree[v].dist = tree[ls].dist, tree[v].from = tree[ls].from;
  if (!tree[rs].used && tree[v].dist > tree[rs].dist)
    tree[v].dist = tree[rs].dist, tree[v].from = tree[rs].from;
  if (tree[v].from == -1) {
    if (!tree[ls].used)
      tree[v].from = tree[ls].from;
    else
      tree[v].from = tree[rs].from;
  }
}
void add_edge(int v, int vl, int vr, int l, int r, edge e) {
  if (vl > r || vr < l) return;
  if (l <= vl && vr <= r) {
    tree[v].edges.push_back(e);
    return;
  }
  int vm = (vl + vr) >> 1;
  add_edge(v << 1, vl, vm, l, r, e);
  add_edge((v << 1) + 1, vm + 1, vr, l, r, e);
}
void build(int v, int vl, int vr, int second) {
  if (vl == vr) {
    pos[vl] = v;
    tree[v].from = vl;
    if (vl == second) tree[v].dist = 0;
    return;
  }
  int vm = (vl + vr) >> 1;
  build(v << 1, vl, vm, second);
  build((v << 1) + 1, vm + 1, vr, second);
  upd(v);
}
void mark(int v) {
  v = pos[v];
  tree[v].used = true;
  while (v > 1) {
    v >>= 1;
    push(v);
    upd(v);
  }
}
void push_all(int v, int vl, int vr) {
  if (vl == vr) return;
  push(v);
  int vm = (vl + vr) >> 1;
  push_all(v << 1, vl, vm);
  push_all((v << 1) + 1, vm + 1, vr);
}
void set_val(int v, int vl, int vr, int l, int r, long long val) {
  if (vl > r || vr < l) return;
  if (l <= vl && vr <= r) {
    chkmin(tree[v].pushed, val);
    chkmin(tree[v].dist, val);
    return;
  }
  push(v);
  int vm = (vl + vr) >> 1;
  set_val(v << 1, vl, vm, l, r, val);
  set_val((v << 1) + 1, vm + 1, vr, l, r, val);
  upd(v);
}
int main() {
  int n, q, second;
  scanf("%d%d%d", &n, &q, &second);
  vector<long long> ans(n + 1, -1);
  tree.resize(4 * n);
  build(1, 1, n, second);
  for (int i = 0; i < q; ++i) {
    int t;
    scanf("%d", &t);
    if (t == 1) {
      int v, u, c;
      scanf("%d%d%d", &v, &u, &c);
      add_edge(1, 1, n, v, v, edge(u, u, c, i));
      continue;
    }
    int v, l, r, c;
    scanf("%d%d%d%d", &v, &l, &r, &c);
    if (t == 2) {
      add_edge(1, 1, n, v, v, edge(l, r, c, i));
    } else {
      add_edge(1, 1, n, l, r, edge(v, v, c, i));
    }
  }
  set<int> kekos;
  while (tree[1].dist != INF && !tree[1].used) {
    int cv = tree[1].from;
    ans[cv] = tree[1].dist;
    long long dist = tree[1].dist;
    int cv1 = cv;
    cv = pos[cv];
    while (cv) {
      if (tree[cv].relaxed) {
        cv >>= 1;
        continue;
      }
      tree[cv].relaxed = true;
      for (auto i : tree[cv].edges) {
        if (used[i.num]) continue;
        used[i.num] = true;
        set_val(1, 1, n, i.l, i.r, dist + i.c);
      }
      cv >>= 1;
    }
    mark(cv1);
  }
  for (int i = 1; i <= n; ++i) {
    printf("%I64d ", ans[i]);
  }
  return 0;
}
