import std.stdio, std.array, std.string, std.conv, std.algorithm;
import std.typecons, std.range, std.random, std.math, std.container;
import std.numeric, std.bigint, core.bitop, std.bitmanip;


void main() {
    auto s = readln.split.map!(to!int);
    auto v = s[0];
    auto e = s[1];
    auto r = s[2];
    auto g = new Edge!(long)[][](v);
    foreach (_; 0..e) {
        s = readln.split.map!(to!int);
        auto x = s[0];
        auto y = s[1];
        auto cost = s[2];
        g[x] ~= Edge!(long)(y, cost);
    }

    auto dist = dijkstra!(long, 1L<<59)(g, r);
    v.iota.map!(i => dist[i] == 1L<<59 ? "INF" : to!string(dist[i])).each!writeln;
}

struct Edge(T) {
    int to;
    T cost;
}

T[] dijkstra(T, T inf)(Edge!(T)[][] graph, int start) {
    import std.typecons : Tuple, tuple;
    import std.conv : to;
    import std.container : BinaryHeap;

    int n = graph.length.to!int;
    auto dist = new T[](n);
    dist[] = inf;
    dist[start] = 0;

    auto pq = new BinaryHeap!(Array!(Edge!(T)), "a.cost > b.cost");
    pq.insert(Edge!(T)(start, 0));

    while (!pq.empty) {
        auto u = pq.front.to;
        auto cost = pq.front.cost;
        pq.removeFront;
        foreach (const e; graph[u]) {
            auto v = e.to;
            auto next_cost = cost + e.cost;
            if (dist[v] <= next_cost) continue;
            dist[v] = next_cost;
            pq.insert(Edge!(T)(v, next_cost));
        }
    }

    return dist;
}

