#include <bits/stdc++.h>

using namespace std;

struct Edge {
  int from, to;
  Edge(int from, int to) : from(from), to(to) {};
};

template<typename Cost> struct WeightedEdge : public Edge {
  typedef Cost CostType;
  Cost cost;
  WeightedEdge(int from, int to, Cost cost) : Edge(from, to), cost(cost) {}
};

template<typename Capacity> struct ResidualEdge : public Edge {
  typedef Capacity CapacityType;
  Capacity cap;
  int rev;
  ResidualEdge(int from, int to, Capacity cap) : Edge(from, to), cap(cap) {}
  ResidualEdge reverse() const {return ResidualEdge(to, from, 0);}
};

template<typename Capacity, typename Cost> struct WeightedResidualEdge : public ResidualEdge<Capacity> {
  Cost cost;
  WeightedResidualEdge(int from, int to, Capacity cap, Cost cost) : ResidualEdge<Capacity>(from, to, cap), cost(cost) {}
  WeightedResidualEdge reverse() const {return WeightedResidualEdge(this->to, this->from, 0, -cost);}
};

template<typename Edge> class Graph {
public:
  virtual int size() const {return 0;};
  virtual void addEdge(const Edge& edge) {(void)edge;};
  virtual void addUndirectedEdge(Edge edge) {(void)edge;};
  virtual vector<Edge> getEdges(int from, int to) const {(void)from; (void)to; return vector<Edge>();};
  virtual int getDegree(int v) const {(void)v; return 0;}
};

template<typename Edge> class AdjacencyList : public Graph<Edge> {
protected:
  vector<vector<Edge>> graph;

public:
  AdjacencyList(int n) : graph(n) {}

  int size() const {
    return graph.size();
  }
  
  void addEdge(const Edge& edge) {
    graph[edge.from].emplace_back(edge);
  }

  void addUndirectedEdge(Edge edge) {
    addEdge(edge);
    swap(edge.from, edge.to);
    addEdge(edge);
  }

  vector<Edge> getEdges(int from, int to) const {
    vector<Edge> res;
    for (const auto& edge : graph[from]) {
      if (edge.to == to) res.emplace_back(edge);
    }
    return res;
  }

  int getDegree(int v) const {
    return graph[v].size();
  }

  vector<Edge>& operator[](int v) {
    return graph[v];
  }
};

template<template<typename Edge> class Graph, typename Edge> class ShortestPath {
private:
  typedef typename Edge::CostType Cost;

  struct State {
    int pos;
    Cost cost;
    bool operator<(const State& state) const {return cost > state.cost;}
  };

  Graph<Edge> graph;

public:
  const Cost INF;

  vector<Cost> dist;

  ShortestPath(const Graph<Edge>& graph) : graph(graph), INF(numeric_limits<Cost>::max()) {}
  
  void run (int from) {
    priority_queue<State> que;
    que.push((State){from, 0});
    dist.resize(graph.size(), INF);
    while (!que.empty()) {
      State now = que.top();
      que.pop();
      if (dist[now.pos] <= now.cost) continue;
      dist[now.pos] = now.cost;
      for (const Edge& edge : graph[now.pos]) {
        if (dist[edge.to] < now.cost + edge.cost) continue;
        que.push((State){edge.to, now.cost + edge.cost});
      }
    }
  }
};

int main() {
  int v, e, r;
  cin >> v >> e >> r;
  AdjacencyList<WeightedEdge<int>> graph(v);
  for (int i = 0; i < e; ++i) {
    int s, t, d;
    cin >> s >> t >> d;
    graph.addEdge(WeightedEdge<int>(s, t, d));
  }
  ShortestPath<AdjacencyList, WeightedEdge<int>> shortestPath(graph);
  shortestPath.run(r);
  for (int c : shortestPath.dist) {
    if (c != shortestPath.INF) cout << c << endl;
    else cout << "INF" << endl;
  }
}

Measured memory_bytes: 24032