#include <iostream>
#include <complex>
#include <sstream>
#include <string>
#include <algorithm>
#include <deque>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <vector>
#include <set>
#include <limits>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
#define REP(i, j) for(int i = 0; i < (int)(j); ++i)
#define FOR(i, j, k) for(int i = (int)(j); i < (int)(k); ++i)
#define SORT(v) sort((v).begin(), (v).end())
#define REVERSE(v) reverse((v).begin(), (v).end())
//typedef complex<double> P;
typedef pair<int, int> P;
const int MAX_V = 100010;
const int INF = 1e9 + 7;

int dijkstra(const vector< vector<P> > &cost, int s, int t, int V){
  priority_queue<P, vector<P>, greater<P> > open;
  open.push(P(s, 0));
  int closed[MAX_V];
  REP(i, V) closed[i] = INF;
  while(!open.empty()){
    P tmp = open.top(); open.pop();
    int now = tmp.first, c = tmp.second;
    if(closed[now] < c) continue;
    closed[now] = c;
    REP(i, cost[now].size()){
      int next = cost[now][i].first, nc = cost[now][i].second;
      if(nc == INF || c + nc >= closed[next]) continue;
      closed[next] = c + nc;
      open.push(P(next, closed[next]));
    }
  }
  REP(i, V){
    if(closed[i] == INF) cout <<"INF" <<endl;
    else cout <<closed[i] <<endl;
  }
  return closed[t];
}

int main() {
  int V, E, r;
  cin >>V >>E >>r;
  vector< vector<P> > cost(V);
  REP(i, E){
    int f, t, c; cin >>f >>t >>c;
    cost[f].push_back(P(t, c));
  }
  //REP(i, E){
  //  if((int)cost[i].size() <= 0) continue;
  //  SORT(cost[i]);
  //  vector<P> tmp;
  //  int now = cost[i][0].first;
  //  tmp.push_back(cost[i][0]);
  //  FOR(j, 1, cost[i].size()){
  //    if(now == cost[i][j].first) continue;
  //    now = cost[i][j].first;
  //    tmp.push_back(cost[i][j]);
  //  }
  //  cost[i] = tmp;
  //}
  dijkstra(cost, r, -1, V);
  return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct edge{ int u,v,cost; };

vector<edge> edges;

int uf_par[10000];
int uf_rank[10000];

void uf_init(int uf_n){
	for(int i = 0;i < uf_n;i++){
		uf_par[i] = i;
		uf_rank[i] = 0;
	}
}

int uf_find(int uf_x){
	if(uf_par[uf_x] == uf_x) return uf_x;
	else return uf_par[uf_x] = uf_find(uf_par[uf_x]);
}

void uf_unite(int uf_x,int uf_y){
	uf_x = uf_find(uf_x);
	uf_y = uf_find(uf_y);
	if(uf_x == uf_y) return;
	if(uf_rank[uf_x] < uf_rank[uf_y]){
		uf_par[uf_x] = uf_y;
	}else{
		uf_par[uf_y] = uf_x;
		if(uf_rank[uf_x] == uf_rank[uf_y]) uf_rank[uf_x]++;
	}
}

bool uf_same(int uf_x,int uf_y){
	return uf_find(uf_x) == uf_find(uf_y);
}

bool krus_comp(const edge& e1, const edge& e2){
	return e1.cost < e2.cost;
}

int kruskal(int V){
	sort(edges.begin(),edges.end(),krus_comp);
	uf_init(V);
	int krus_res = 0;
	for(int i = 0;i < edges.size();i++){
		edge krus_e = edges[i];
		if(!uf_same(krus_e.u,krus_e.v)){
			uf_unite(krus_e.u,krus_e.v);
			krus_res += krus_e.cost;
		}
	}
	return krus_res;
}

int main(){
	int V,E;
	cin >> V >> E;
	for(int i = 0;i < E;i++){
		int a,b,c;
		cin >> a >> b >> c;
		edges.push_back({a,b,c});
	}
	cout << kruskal(V) << endl;
	return 0;
}