using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

using static util;
using P = pair<int, int>;

class Program
{
    static StreamWriter sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
    static Scan sc = new Scan();
    const int M = 1000000007;
    // const int M = 998244353;
    static void Main()
    {
        int n, m, s;
        sc.Multi(out n, out m, out s);
        // --s;
        var edges = new List<pair<long, int>>[n];
        for (int i = 0; i < n; i++)
        {
            edges[i] = new List<pair<long, int>>();
        }
        for (int i = 0; i < m; i++)
        {
            int f, t, c;
            sc.Multi(out f, out t, out c);
            // --f;
            // --t;
            edges[f].Add(make_pair((long)c, t));
        }
        sw.WriteLine(MSA.getmincost(edges, s));
        sw.Flush();
    }
}
class pair<T, U> : IComparable<pair<T, U>> where T : IComparable<T> where U : IComparable<U>
{
    public T v1;
    public U v2;
    public pair(T v1, U v2) {
        this.v1 = v1;
        this.v2 = v2;
    }
    public int CompareTo(pair<T, U> a) { return v1.CompareTo(a.v1) != 0 ? v1.CompareTo(a.v1) : v2.CompareTo(a.v2); }
    public override string ToString() { return v1 + " " + v2; }
}
static class util
{
    public static pair<T, U> make_pair<T, U>(T v1, U v2) where T : IComparable<T> where U : IComparable<U> { return new pair<T, U>(v1, v2); }
    public static void swap<T>(ref T a, ref T b) { var t = a; a = b; b = t; }
    public static void swap<T>(this IList<T> a, int i, int j) { var t = a[i]; a[i] = a[j]; a[j] = t; }
    public static T[] copy<T>(this IList<T> a) {
        var ret = new T[a.Count];
        for (int i = 0; i < a.Count; i++) ret[i] = a[i];
        return ret;
    }
}

class Scan
{
    public string Str { get { return Console.ReadLine().Trim(); } }
    public string[] StrArr { get { return Str.Split(new []{' '}, System.StringSplitOptions.RemoveEmptyEntries); } }
    bool eq<T, U>() { return typeof(T).Equals(typeof(U)); }
    T ct<T, U>(U a) { return (T)Convert.ChangeType(a, typeof(T)); }
    T cv<T>(string s) { return eq<T, int>()    ? ct<T, int>(int.Parse(s))
                       : eq<T, long>()   ? ct<T, long>(long.Parse(s))
                       : eq<T, double>() ? ct<T, double>(double.Parse(s))
                       : eq<T, char>()   ? ct<T, char>(s[0])
                                         : ct<T, string>(s); }
    public void Multi<T, U>(out T a, out U b)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); }
    public void Multi<T, U, V>(out T a, out U b, out V c)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); }
    public void Multi<T, U, V, W>(out T a, out U b, out V c, out W d)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); d = cv<W>(ar[3]); }
    public void Multi<T, U, V, W, X>(out T a, out U b, out V c, out W d, out X e)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); d = cv<W>(ar[3]); e = cv<X>(ar[4]); }
    public void Multi<T, U, V, W, X, Y>(out T a, out U b, out V c, out W d, out X e, out Y f)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); d = cv<W>(ar[3]); e = cv<X>(ar[4]); f = cv<Y>(ar[5]); }
}

// 最小有向全域木
static class MSA
{
    class node {
        PriorityQueue<pair<long, int>> come_edges;
        long additional_cost;

        // init
        public node() {
            come_edges = new PriorityQueue<pair<long, int>>(){ rev = true };
            additional_cost = 0;
        }
        public void push_edge(pair<long, int> e) {
            e.v1 -= additional_cost;
            come_edges.Push(e);
        }
        public pair<long, int> pop_edge() {
            var ret = come_edges.Pop();
            ret.v1 += additional_cost;
            return ret;
        }
        public long add_cost(long ad) { return additional_cost += ad; }
        public int edge_cnt { get { return come_edges.Count; } }

        // hakai-teki
        public static node merge(node a, node b) {
            if (a.edge_cnt < b.edge_cnt) return merge(b, a);
            while (b.edge_cnt > 0) {
                var e = b.pop_edge();
                a.push_edge(e);
            }
            return a;
        }
    }
    public static long getmincost(List<pair<long, int>>[] edges, int root) {
        int n = edges.Length;
        var nodes = new node[n];
        for (int i = 0; i < n; i++)
        {
            nodes[i] = new node();
        }
        for (int i = 0; i < n; i++)
        {
            foreach (var item in edges[i])
                nodes[item.v2].push_edge(make_pair(item.v1, i));
        }
        var leaf_node = new int[n];
        for (int i = 0; i < n; i++)
        {
            leaf_node[i] = -1;
        }
        leaf_node[root] = root;
        var uf_zipped = new UnionFind(n);
        var uf_connected = new UnionFind(n);
        long ret = 0;
        for (int i = 0; i < n; i++)
        {
            var st = new Stack<pair<long, int>>();
            for (int j = uf_zipped.getpar(i); leaf_node[j] == -1; )
            {
                leaf_node[j] = i;
                if (nodes[j].edge_cnt == 0) return -1;
                var e = nodes[j].pop_edge();
                e.v2 = uf_zipped.getpar(e.v2);
                if (j == e.v2) continue;
                st.Push(e);
                ret += e.v1;
                nodes[j].add_cost(-e.v1);
                if (uf_connected.same(j, e.v2)) {
                    uf_zipped.unite(j, e.v2);
                    nodes[uf_zipped.getpar(j)] = node.merge(nodes[j], nodes[e.v2]);
                    j = uf_zipped.getpar(j);
                    while (st.Any()) {
                        var ee = st.Peek();
                        if (uf_zipped.getpar(e.v2) == j) break;

                        st.Pop();
                        uf_zipped.unite(j, ee.v2);
                        nodes[uf_zipped.getpar(j)] = node.merge(nodes[j], nodes[e.v2]);
                        j = uf_zipped.getpar(j);
                    }
                    leaf_node[j] = -1;
                }
                else {
                    uf_connected.unite(j, e.v2);
                    j = e.v2;
                }
            }
        }
        return ret;
    }
}
class UnionFind
{
    int num;
    int[] par, sz, rank;
    public UnionFind(int n) {
        num = n; par = new int[n]; sz = new int[n]; rank = new int[n];
        for (int i = 0; i < n; ++i) { par[i] = i; sz[i] = 1; rank[i] = 0; }
    }
    int find(int x) => par[x] == x ? x : (par[x] = find(par[x]));
    public bool same(int x, int y) { return find(x) == find(y); }
    public int unionsize(int x) { return sz[find(x)]; }
    public bool unite(int x, int y) {
        x = find(x); y = find(y);
        if (x == y) return false;
        --num;
        if (rank[x] < rank[y]) {
            par[x] = y;
            sz[y] += sz[x];
        }
        else {
            par[y] = x;
            sz[x] += sz[y];
            if (rank[x] == rank[y]) ++rank[x];
        }
        return true;
    }
    public bool ispar(int x) { return x == find(x); }
    public int getpar(int x) { return find(x); }
}

// the greatest element pops
class PriorityQueue<T> where T : IComparable<T> {
    List<T> buf;
    public bool rev = false;
    public PriorityQueue() { buf = new List<T>(); }
    int cmp(int i, int j) { return buf[i].CompareTo(buf[j]) * (rev ? -1 : 1); }
    void swap(int i, int j) { var t = buf[i]; buf[i] = buf[j]; buf[j] = t; }
    public void Push(T elem) {
        int n = buf.Count;
        buf.Add(elem);
        while (n > 0) {
            int i = (n - 1) >> 1;
            if (cmp(n, i) > 0) swap(i, n);
            n = i;
        }
    }
    public T Pop() {
        T ret = buf[0];
        int n = buf.Count - 1;
        buf[0] = buf[n];
        buf.RemoveAt(n);
        for (int i = 0, j; (j = (i << 1) + 1) < n; i = j) {
            if (j != n - 1 && cmp(j, j + 1) < 0) ++j;
            if (cmp(i, j) < 0) swap(i, j);
        }
        return ret;
    }
    public T Top { get { return buf[0]; } }
    public int Count { get { return buf.Count; } }

    // hakai-teki
    static PriorityQueue<T> merge(PriorityQueue<T> q1, PriorityQueue<T> q2) {
        if (q1.Count < q2.Count) return merge(q2, q1);
        while (q2.Count > 0) q1.Push(q2.Pop());
        return q1;
    }
}

