text: #include <bits/stdc++.h>
  using namespace std;
  
  typedef long long int ll;
  
  void __print(int x) {cerr << x;}
  void __print(long x) {cerr << x;}
  void __print(long long x) {cerr << x;}
  void __print(unsigned x) {cerr << x;}
  void __print(unsigned long x) {cerr << x;}
  void __print(unsigned long long x) {cerr << x;}
  void __print(float x) {cerr << x;}
  void __print(double x) {cerr << x;}
  void __print(long double x) {cerr << x;}
  void __print(char x) {cerr << '\'' << x << '\'';}
  void __print(const char *x) {cerr << '\"' << x << '\"';}
  void __print(const string &x) {cerr << '\"' << x << '\"';}
  void __print(bool x) {cerr << (x ? "true" : "false");}
  
  template<typename T, typename V>
  void __print(const pair<T, V> &x) {cerr << '{'; __print(x.first); cerr << ','; __print(x.second); cerr << '}';}
  template<typename T>
  void __print(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), __print(i); cerr << "}";}
  void _print() {cerr << "]\n";}
  template <typename T, typename... V>
  void _print(T t, V... v) {__print(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
  
  #ifndef ONLINE_JUDGE
  #define debug(x...) cerr << "[" << #x << "] = ["; _print(x)
  #else
  #define debug(x...)
  #endif
  
  #define faster  ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
  #define all(x) x.begin(), x.end()
  #define sum(a)     ( accumulate ((a).begin(), (a).end(), 0ll))
  #define mine(a)    (*min_element((a).begin(), (a).end()))
  #define maxe(a)    (*max_element((a).begin(), (a).end()))
  #define mini(a)    ( min_element((a).begin(), (a).end()) - (a).begin())
  #define maxi(a)    ( max_element((a).begin(), (a).end()) - (a).begin())
  #define lowb(a, x) ( lower_bound((a).begin(), (a).end(), (x)) - (a).begin())
  #define uppb(a, x) ( upper_bound((a).begin(), (a).end(), (x)) - (a).begin())
  
  #define mp   make_pair
  #define pb   push_back
  #define eb   emplace_back
  
  template<typename T>             vector<T>& operator--            (vector<T> &v){for (auto& i : v) --i;            return  v;}
  template<typename T>             vector<T>& operator++            (vector<T> &v){for (auto& i : v) ++i;            return  v;}
  template<typename T>             istream& operator>>(istream& is,  vector<T> &v){for (auto& i : v) is >> i;        return is;}
  template<typename T>             ostream& operator<<(ostream& os,  vector<T>  v){for (auto& i : v) os << i << ' '; return os;}
  template<typename T, typename U> pair<T,U>& operator--           (pair<T, U> &p){--p.first; --p.second;            return  p;}
  template<typename T, typename U> pair<T,U>& operator++           (pair<T, U> &p){++p.first; ++p.second;            return  p;}
  template<typename T, typename U> istream& operator>>(istream& is, pair<T, U> &p){is >> p.first >> p.second;        return is;}
  template<typename T, typename U> ostream& operator<<(ostream& os, pair<T, U>  p){os << p.first << ' ' << p.second; return os;}
  template<typename T, typename U> pair<T,U> operator-(pair<T,U> a, pair<T,U> b){return mp(a.first-b.first, a.second-b.second);}
  template<typename T, typename U> pair<T,U> operator+(pair<T,U> a, pair<T,U> b){return mp(a.first+b.first, a.second+b.second);}
  template<typename T, typename U> void umin(T& a, U b){if (a > b) a = b;}
  template<typename T, typename U> void umax(T& a, U b){if (a < b) a = b;}
  template<typename T>
  bool exist_vector(vector<T> v, T x){return (find(v.begin(), v.end(), x) != v.end()) ? true : false;} // unsorted
  
  struct compare {
      bool operator()(pair<int, int> a, pair<int, int> b){
          return a.first > b.first;
      }
  };
  
  vector<int> dijkstra(int start, int n, vector<unordered_map<int, int>> graph){
      vector<int> dists(n+1, INT_MAX);
      dists[start] = 0;
      priority_queue<pair<int, int>, vector<pair<int, int>>, compare> q;
      q.push(make_pair(0, start));
      while (!q.empty()){
          auto [dist, node] = q.top();
          debug(dist, node);
          q.pop();
          if (dist > dists[node]) continue;
          assert (dist == dists[node]);
          for (auto [to_node, to_dist] : graph[node]){
              int new_dist = dist + to_dist;
              if (new_dist < dists[to_node]){
                  dists[to_node] = new_dist;
                  q.push(make_pair(new_dist, to_node));
              }
          }
      }
      return dists;
  }
  
  int main(){
  #ifndef ONLINE_JUDGE
      freopen("input.txt", "r", stdin);
      freopen("output.txt", "w", stdout);
  #else
  #endif
      faster
      int v, e, k;
      cin >> v >> e >> k;
      vector<unordered_map<int, int>> graph(v+1, unordered_map<int, int>{});
      while (e--){
          int u, v, w;
          cin >> u >> v >> w;
          debug(u, v, w);
          auto m = &graph[u];
          if (m->find(v) != m->end()){
              if (m->at(v) <= w) continue;
          }
          graph[u][v] = w;
      }
  
      debug(graph);
  
      vector<int> dists = dijkstra(k, v, graph);
      for (int i=1; i<=v; i++){
          int d = dists[i];
          if (d == INT_MAX) cout << "INF\n";
          else cout << d << '\n';
      }
      return 0;
  }