import std.algorithm,
       std.container,
       std.typetuple,
       std.typecons,
       std.string,
       std.array,
       std.stdio,
       std.conv;

const INF = (1<<30);
alias Edge = Tuple!(int, "to",int , "cost");
alias tie = TypeTuple;

int[] dijkstra(in Edge[][] tree, int start) {
  alias PriorityQueue = BinaryHeap;

  size_t V = tree.length;
  auto dist = new int[V];
  fill(dist, INF);

  auto queue = new PriorityQueue!(Array!Edge, "a.cost>=b.cost")();

  dist[start] = 0;
  queue.insert(Edge(start,0));
  while (!queue.empty()) {
    int v;
    int cost;
    tie!(v, cost) = queue.front();
    queue.popFront();

    if (dist[v] < cost) {
      continue;
    }
    foreach(const ref Edge e; tree[v]) {
      if (dist[v] + e.cost < dist[e.to]) {
        dist[e.to] = dist[v] + e.cost;
        queue.insert(Edge(e.to, dist[e.to]));
      }
    }
  }

  return dist;
}

void readlnToken(T...)(auto ref T args) {
  auto line = split(readln());
  foreach(ref arg; args) {
    arg = to!(typeof(arg))(line[0]);
    line = line[1..$];
  }
  assert(line.empty());
}

void main() {
  int V, E, r;
  readlnToken(V, E, r);

  auto tree = new Edge[][](V,0);
  foreach(i; 0..E)  {
    int s, t, d;
    readlnToken(s,t,d);
    tree[s] ~= Edge(t, d);
  }

  auto dists = dijkstra(tree, r);
  foreach (dist; dists) {
    if (dist == INF) {
      writeln("INF");
    } else {
      writeln(dist);
    }
  }
}

