use std::collections::BinaryHeap;
use std::cmp::*;

// use graph::graph::*;

pub type Weight = i32;

#[derive(Clone, Hash, Debug, Default)]
pub struct Edge {
    pub src: usize,
    pub dst: usize,
    pub weight: Weight,
}

impl Edge {
    fn new(src: usize, dst: usize, weight: Weight) -> Edge {
        Edge {
            src: src,
            dst: dst,
            weight: weight
        }
    }
}

pub type Edges = Vec<Edge>;
pub type Graph = Vec<Edges>;

pub fn add_weighted_arc(graph: &mut Graph, src: usize, dst: usize, weight: Weight) {
    graph[src].push(Edge::new(src, dst, weight));
}

pub fn add_weighted_edge(graph: &mut Graph, src: usize, dst: usize, weight: Weight) {
    add_weighted_arc(graph, src, dst, weight);
    add_weighted_arc(graph, dst, src, weight);
}

pub fn add_arc(graph: &mut Graph, src: usize, dst: usize) {
    add_weighted_arc(graph, src, dst, 1);
}

pub fn add_edge(graph: &mut Graph, src: usize, dst: usize) {
    add_weighted_edge(graph, src, dst, 1);
}

// use std::io::Read;

// fn read(s: &mut StdinLock) -> Flow {
//     s.bytes()
//         .map(|c| c.expect("failed to read char") as char) 
//         .skip_while(|c| c.is_whitespace())
//         .take_while(|c| !c.is_whitespace())
//         .fold(0, |acc, x| acc * 10 + (x as u8 - b'0') as u64)
// }

// pub fn read_weighted_bidrectional_graph(r: &mut Read) -> Graph {
//     fn read_usize(s: &mut Read) -> usize {
//         s.bytes()
//             .map(|c| c.expect("failed to read char") as char) 
//             .skip_while(|c| c.is_whitespace())
//             .take_while(|c| !c.is_whitespace())
//             .fold(0, |acc, x| acc * 10 + (x as u8 - b'0') as usize)
//     }

//     fn read_weight(s: &mut Read) -> Weight {
//         s.bytes()
//             .map(|c| c.expect("failed to read char") as char) 
//             .skip_while(|c| c.is_whitespace())
//             .take_while(|c| !c.is_whitespace())
//             .fold(0, |acc, x| acc * 10 + (x as u8 - b'0') as Weight)
//     }

//     let (n, m) = (read_usize(r), read_usize(r));
//     let mut graph = vec![vec![]; n];
//     for _ in 0..m {
//         let a = read_usize(r);
//         let b = read_usize(r);
//         let c = read_weight(r);
//         add_weighted_arc(&mut graph, a, b, c);
//     }
//     graph
// }

#[derive(PartialEq, Eq, Clone, Copy)]
struct DijkstraState(usize, Weight);

impl Ord for DijkstraState {
    fn cmp(&self, other: &DijkstraState) -> Ordering {
        // other.1.cmp(&self.1).then_with(|| self.0.cmp(&other.0))
        let c = other.1.cmp(&self.1);
        if c != Ordering::Equal {
            c
        } else {
            self.0.cmp(&other.0)
        }
    }
}

impl PartialOrd for DijkstraState {
    fn partial_cmp(&self, other: &DijkstraState) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

pub fn dijkstra(graph: &Graph, src: usize) -> Vec<Option<Weight>> {
    let INF = Weight::max_value();
    let mut heap = BinaryHeap::<DijkstraState>::new();
    heap.push(DijkstraState(src, 0));
    let mut dist = vec![INF; graph.len()];
    dist[src] = 0;
    while let Some(DijkstraState(v, d)) = heap.pop() {
        if dist[v] == d {
            for e in graph[v].iter() {
                if dist[e.dst] > d + e.weight {
                    dist[e.dst] = d + e.weight;
                    heap.push(DijkstraState(e.dst, dist[e.dst]));
                }
            }
        }
    }
    dist.iter().map(|&d| if d != INF { Some(d) } else { None }).collect()
}

pub fn dijkstra_to(graph: &Graph, src: usize, dst: usize) -> Option<Weight> {
    if src == dst {
        Some(0)
    } else {
        let mut heap = BinaryHeap::new();
        heap.push(DijkstraState(src, 0));
        let mut dist = vec![Weight::max_value(); graph.len()];
        dist[src] = 0;
        let mut res = None;
        while let Some(DijkstraState(v, d)) = heap.pop() {
            if v == dst {
                res = Some(d);
                break;
            }
            if dist[v] == d {
                for e in graph[v].iter() {
                    if dist[e.dst] > d + e.weight {
                        dist[e.dst] = d + e.weight;
                        heap.push(DijkstraState(e.dst, dist[e.dst]));
                    }
                }
            }
        }
        res
    }
}

pub fn bidirectional_dijkstra(graph: &Graph, src: usize, dst: usize) -> Option<Weight> {
    if src == dst {
        Some(0)
    } else {
        let INF: Weight = Weight::max_value();
        let n = graph.len();
        let mut heaps = [BinaryHeap::new(), BinaryHeap::new()];
        heaps[0].push(DijkstraState(src, 0));
        heaps[1].push(DijkstraState(dst, 0));
        let mut dists = [vec![INF; n], vec![INF; n]];
        dists[0][src] = 0;
        dists[1][src] = 0;

        let mut mu = INF;

        while !heaps[0].is_empty() && !heaps[1].is_empty() {
            let k = {
                let tops = [heaps[0].peek().unwrap(), heaps[1].peek().unwrap()];
                if tops[0].1 + tops[1].1 >= mu {
                    break;
                }
                if tops[0].1 <= tops[1].1 {
                    0
                } else {
                    1
                }
            };

            let DijkstraState(v, d) = heaps[k].pop().unwrap();
            if dists[k][v] == d {
                for e in graph[v].iter() {
                    if dists[k][e.dst] > d + e.weight {
                        dists[k][e.dst] = d + e.weight;
                        heaps[k].push(DijkstraState(e.dst, dists[k][e.dst]));
                        mu = min(mu, dists[k][e.src] + e.weight + dists[k][1 - k]); 
                    }
                }
            }
        }

        if mu != INF {
            Some(mu)
        } else {
            None
        }
    }
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_1_A&lang=jp
use std::io::*;

fn read(s: &mut StdinLock) -> Weight {
    s.bytes()
        .map(|c| c.expect("failed to read char") as char) 
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .fold(0, |acc, x| acc * 10 + (x as u8 - b'0') as Weight)
}

fn main() {
    let stdin = stdin();
    let mut stdin = stdin.lock();
    let stdin = &mut stdin;

    let n = read(stdin) as usize;
    let m = read(stdin) as usize;
    let r = read(stdin) as usize;
    let mut g = vec![vec![]; n];
    for _ in 0..m {
        let a = read(stdin) as usize;
        let b = read(stdin) as usize;
        let c = read(stdin);
        add_weighted_arc(&mut g, a, b, c);
    }

    let mut s = String::new();
    let d = dijkstra(&g, r);
    for e in d.iter() {
        if let Some(d) = *e {
            s += d.to_string().as_str();
        } else {
            s += "INF";
        }
        s += "\n";
    }
    print!("{}", s);
}



Measured memory_bytes: 27456