#include <bits/stdc++.h>
using namespace std;
const long long inf = 1e18 + 5;
const int mod = 1e8;
const int Max = 1e5 + 10;
struct Node {
  int l, r;
  int num;
} node1[Max << 3], node2[Max << 3];
struct Edge {
  int to;
  long long dis;
};
vector<Edge> edge[Max << 3];
int pos1[Max << 3], pos2[Max << 3];
int n, q, s;
int tot;
void build_up(int l, int r, int num) {
  node1[num].l = l;
  node1[num].r = r;
  node1[num].num = ++tot;
  if (l == r) {
    pos1[l] = node1[num].num;
    return;
  }
  int mid = (l + r) >> 1;
  build_up(l, mid, num << 1);
  build_up(mid + 1, r, num << 1 | 1);
  edge[node1[num << 1].num].push_back({node1[num].num, 0});
  edge[node1[num << 1 | 1].num].push_back({node1[num].num, 0});
}
void build_down(int l, int r, int num) {
  node2[num].l = l;
  node2[num].r = r;
  node2[num].num = ++tot;
  if (l == r) {
    pos2[l] = node2[num].num;
    edge[node2[num].num].push_back({pos1[l], 0});
    return;
  }
  int mid = (l + r) >> 1;
  build_down(l, mid, num << 1);
  build_down(mid + 1, r, num << 1 | 1);
  edge[node2[num].num].push_back({node2[num << 1].num, 0});
  edge[node2[num].num].push_back({node2[num << 1 | 1].num, 0});
}
void upData_section_to_dot(int l, int r, int v, long long dis, int num) {
  if (l <= node1[num].l && node1[num].r <= r) {
    edge[node1[num].num].push_back({pos2[v], dis});
    return;
  }
  int mid = (node1[num].l + node1[num].r) >> 1;
  if (l <= mid) upData_section_to_dot(l, r, v, dis, num << 1);
  if (r > mid) upData_section_to_dot(l, r, v, dis, num << 1 | 1);
}
void upData_dot_to_section(int l, int r, int u, long long dis, int num) {
  if (l <= node2[num].l && node2[num].r <= r) {
    edge[pos1[u]].push_back({node2[num].num, dis});
    return;
  }
  int mid = (node2[num].l + node2[num].r) >> 1;
  if (l <= mid) upData_dot_to_section(l, r, u, dis, num << 1);
  if (r > mid) upData_dot_to_section(l, r, u, dis, num << 1 | 1);
}
bool vis[Max << 3];
long long dist[Max << 3];
void dijkstra(int start) {
  memset(vis, 0, sizeof(vis));
  for (int i = 1; i <= 8 * n; i++) dist[i] = inf;
  dist[start] = 0;
  priority_queue<pair<long long, int>, vector<pair<long long, int> >,
                 greater<pair<long long, int> > >
      queues;
  queues.push({0, start});
  while (!queues.empty()) {
    int u = queues.top().second;
    queues.pop();
    if (vis[u]) continue;
    vis[u] = true;
    for (int i = 0; i < edge[u].size(); i++) {
      int v = edge[u][i].to;
      long long dis = edge[u][i].dis;
      if (vis[v]) continue;
      if (dist[v] > dist[u] + dis) {
        dist[v] = dist[u] + dis;
        queues.push({dist[v], v});
      }
    }
  }
  for (int i = 1; i <= n; i++) {
    if (dist[pos1[i]] != inf)
      printf("%lld ", dist[pos1[i]]);
    else
      printf("-1 ");
  }
  printf("\n");
}
int main() {
  while (scanf("%d%d%d", &n, &q, &s) != EOF) {
    for (int i = 0; i < Max << 3; i++) edge[i].clear();
    tot = 0;
    build_up(1, n, 1);
    build_down(1, n, 1);
    while (q--) {
      int type, u, v, l, r;
      long long cost;
      scanf("%d", &type);
      if (type == 1) {
        scanf("%d%d%lld", &u, &v, &cost);
        edge[pos1[u]].push_back({pos2[v], cost});
      } else if (type == 2) {
        scanf("%d%d%d%lld", &u, &l, &r, &cost);
        upData_dot_to_section(l, r, u, cost, 1);
      } else {
        scanf("%d%d%d%lld", &v, &l, &r, &cost);
        upData_section_to_dot(l, r, v, cost, 1);
      }
    }
    dijkstra(pos1[s]);
  }
  return 0;
}
