#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void *xmalloc(size_t size) {
  void *ptr = malloc(size);
  if (ptr == NULL) {
    fprintf(stderr, "Failed to allocate memory\n");
    exit(EXIT_FAILURE);
  }
  return ptr;
}

typedef struct {
  void **data;
  size_t capacity;
  size_t len;
} Vector;

#define VECTOR_DEFAULT_CAPACITY 16

Vector *new_vec_with(size_t capacity) {
  Vector *v = xmalloc(sizeof(Vector));
  v->data = xmalloc(sizeof(void *) * capacity);
  v->capacity = capacity;
  v->len = 0;
  return v;
}

Vector *new_vec() { return new_vec_with(VECTOR_DEFAULT_CAPACITY); }

void vec_expand(Vector *v, size_t size) {
  if (v->len < size) {
    v->capacity = size;
    v->len = size;
    v->data = realloc(v->data, sizeof(void *) * v->capacity);
  }
}

void vec_push(Vector *v, void *elem) {
  if (v->len == v->capacity) {
    v->capacity *= 2;
    v->data = realloc(v->data, sizeof(void *) * v->capacity);
  }
  v->data[v->len++] = elem;
}

void *vec_pop(Vector *v) {
  assert(v->len);
  return v->data[--v->len];
}

#define VecForeachWithType(vec, T, loop_val, loop_body)                        \
  for (size_t fe_loop_counter_##vec = 0; fe_loop_counter_##vec < vec->len;     \
       fe_loop_counter_##vec++) {                                              \
    T loop_val = vec->data[fe_loop_counter_##vec];                             \
    loop_body;                                                                 \
  }

#define VecForeach(vec, loop_val, loop_body)                                   \
  VecForeachWithType(vec, void *, loop_val, loop_body)

typedef int (*ELEM_COMPARE)(void *, void *);

typedef struct {
  Vector *vec;
  ELEM_COMPARE compare;
} BinaryHeap;

#define GetHeapVec(heap) (heap->vec)
#define GetHeapData(heap, i) (heap->vec->data[i])

BinaryHeap *new_BinaryHeap(ELEM_COMPARE compare) {
  BinaryHeap *heap = xmalloc(sizeof(BinaryHeap));
  heap->vec = new_vec();
  heap->compare = compare;
  return heap;
}

void heap_insert(BinaryHeap *heap, void *val) {
  size_t n = GetHeapVec(heap)->len;
  vec_push(GetHeapVec(heap), val);

  while (n != 0) {
    size_t i = (n - 1) / 2;

    // heap->vec->data[n] > heap->vec->data[i]
    if (heap->compare(GetHeapData(heap, n), GetHeapData(heap, i)) == 1) {
      void *tmp = GetHeapData(heap, n);
      GetHeapData(heap, n) = GetHeapData(heap, i);
      GetHeapData(heap, i) = tmp;
    }

    n = i;
  }
}

void *heap_pop(BinaryHeap *heap) {
  assert(GetHeapVec(heap)->len > 0);

  size_t n = GetHeapVec(heap)->len - 1;
  void *ret = GetHeapData(heap, 0);
  GetHeapData(heap, 0) = GetHeapData(heap, n);
  vec_pop(GetHeapVec(heap));

  for (size_t i = 0, j; (j = 2 * i + 1) < n;) {
    if ((j != n - 1) &&
        heap->compare(GetHeapData(heap, j), GetHeapData(heap, j + 1)) == -1) {
      j++;
    }

    if (heap->compare(GetHeapData(heap, i), GetHeapData(heap, j)) == -1) {
      void *tmp = GetHeapData(heap, j);
      GetHeapData(heap, j) = GetHeapData(heap, i);
      GetHeapData(heap, i) = tmp;
    }

    i = j;
  }

  return ret;
}

bool heap_empty(BinaryHeap *heap) { return GetHeapVec(heap)->len == 0; }

typedef struct {
  BinaryHeap *heap;
} PriorityQueue;

PriorityQueue *new_PriorityQueue(ELEM_COMPARE compare) {
  PriorityQueue *pqueue = xmalloc(sizeof(PriorityQueue));
  pqueue->heap = new_BinaryHeap(compare);
  return pqueue;
}

void pqueue_push(PriorityQueue *pqueue, void *elem) {
  heap_insert(pqueue->heap, elem);
}

void *pqueue_pop(PriorityQueue *pqueue) { return heap_pop(pqueue->heap); }

bool pqueue_empty(PriorityQueue *pqueue) { return heap_empty(pqueue->heap); }

const int INF = 1 << 30;

typedef struct {
  int dst;
  int cost;
} Edge;

Edge *new_Edge(int dst, int cost) {
  Edge *edge = xmalloc(sizeof(Edge));
  edge->dst = dst;
  edge->cost = cost;
  return edge;
}

static int cmp_Edge(void *lhs, void *rhs) {
  Edge *le = (Edge *)lhs;
  Edge *re = (Edge *)rhs;

  if (le->cost >= re->cost) {
    return 1;
  } else {
    return -1;
  }
}

#define INT_TO_VoPTR(i) ((void *)(intptr_t)i)
#define VoPTR_TO_INT(ptr) ((int)(intptr_t)ptr)

int *dijkstra(Edge ***tree, int V, int src) {
  int *dist = xmalloc(sizeof(int) * V);
  for (size_t i = 0; i < V; i++) {
    dist[i] = INF;
  }

  PriorityQueue *pqueue = new_PriorityQueue(cmp_Edge);

  dist[src] = 0;
  pqueue_push(pqueue, new_Edge(src, 0));

  while (!pqueue_empty(pqueue)) {
    Edge *e = pqueue_pop(pqueue);
    int v = e->dst, cost = e->cost;

    if (dist[v] < cost) {
      continue;
    }

    Edge **vec = tree[v];
    for (int i = 0; i < V; i++) {
      Edge *e = vec[i];
      if (dist[v] + e->cost < dist[e->dst]) {
        dist[e->dst] = dist[v] + e->cost;
        pqueue_push(pqueue, new_Edge(e->dst, dist[e->dst]));
      }
    }
  }

  return dist;
}

int main(void) {
  int V, E, r;
  scanf("%d%d%d", &V, &E, &r);
  int **dp = xmalloc(sizeof(int *) * V);
  for (int i = 0; i < V; i++) {
    dp[i] = xmalloc(sizeof(int) * V);
    for (int j = 0; j < V; j++) {
      dp[i][j] = INF;
    }
  }

  for (int i = 0; i < E; i++) {
    int s, t, d;
    scanf("%d%d%d", &s, &t, &d);
    dp[s][t] = d;
  }

  Edge ***tree = xmalloc(sizeof(Edge **) * V);
  for (int i = 0; i < V; i++) {
    tree[i] = xmalloc(sizeof(Edge **) * V);
    for (int j = 0; j < V; j++) {
      tree[i][j] = new_Edge(j, dp[i][j]);
    }
  }

  for (int i = 0; i < V; i++) {
    free(dp[i]);
  }
  free(dp);

  int *ret = dijkstra(tree, V, r);

  for (int i = 0; i < V; i++) {
    int result = ret[i];
    if (result >= INF) {
      printf("INF\n");
    } else {
      printf("%ld\n", result);
    }
  }

  return 0;
}

