// Verificador de "La capacidad de una red": verificador ENTRADA ESPERADA SALIDA.
// En ESPERADA está solo la cantidad máxima. Se comprueba que salga esa cantidad, que los tramos
// sean válidos y distintos, que su capacidad sume esa cantidad y que, sin ellos, s ya no llegue a t.
// Un conjunto así no tiene tramos de sobra: los que salen de lo que s todavía alcanza ya están en
// él y suman al menos la cantidad máxima, y toda capacidad es al menos 1.
// Termina con 0 si todo está bien, y con 1 y un mensaje si no.
#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <queue>
#include <string>
#include <vector>

namespace {

[[noreturn]] void reject(const std::string& reason) {
    std::cout << reason << '\n';
    std::exit(1);
}

// Convierte una palabra en número sin riesgo de overflow: solo dígitos, y a lo sumo 18.
bool parse_number(const std::string& word, long long& value) {
    if (word.empty() || word.size() > 18) return false;
    value = 0;
    for (char c : word) {
        if (c < '0' || c > '9') return false;
        value = value * 10 + (c - '0');
    }
    return true;
}

}  // namespace

int main(int argc, char* argv[]) {
    if (argc != 4) reject("uso: verificador ENTRADA ESPERADA SALIDA");
    std::ifstream input(argv[1]);
    std::ifstream expected(argv[2]);
    std::ifstream output(argv[3]);

    std::size_t n = 0;
    std::size_t m = 0;
    std::size_t s = 0;
    std::size_t t = 0;
    input >> n >> m >> s >> t;
    std::vector<std::size_t> from(m);
    std::vector<std::size_t> to(m);
    std::vector<long long> capacity(m);
    for (std::size_t k = 0; k < m; k++) input >> from[k] >> to[k] >> capacity[k];

    long long maximum = 0;
    expected >> maximum;

    std::string word;
    long long amount = 0;
    if (!(output >> word) || !parse_number(word, amount)) reject("la primera palabra no es un número válido");
    if (amount != maximum) reject("cantidad máxima esperada: " + std::to_string(maximum) + ", salió " + word);

    long long count = 0;
    if (!(output >> word) || !parse_number(word, count)) reject("falta la cantidad de tramos");
    if (count > static_cast<long long>(m)) reject("hay más tramos en la lista que en la red");

    std::vector<char> closed(m, 0);
    long long total = 0;
    for (long long k = 0; k < count; k++) {
        long long number = 0;
        if (!(output >> word)) reject("faltan tramos en la lista");
        if (!parse_number(word, number)) reject("número de tramo inválido: " + word);
        if (number < 1 || number > static_cast<long long>(m)) reject("tramo fuera de rango: " + word);
        const std::size_t edge = static_cast<std::size_t>(number - 1);
        if (closed[edge]) reject("tramo repetido: " + word);
        closed[edge] = 1;
        total += capacity[edge];
    }
    if (output >> word) reject("sobra texto después de la lista: " + word);
    if (total != maximum) {
        reject("los tramos suman " + std::to_string(total) + " en lugar de " + std::to_string(maximum));
    }

    // Sin los tramos de la lista, t no se debe poder alcanzar desde s.
    std::vector<std::vector<std::size_t>> out(n + 1);
    for (std::size_t k = 0; k < m; k++) {
        if (!closed[k]) out[from[k]].push_back(to[k]);
    }
    std::vector<char> seen(n + 1, 0);
    std::queue<std::size_t> pending;
    seen[s] = 1;
    pending.push(s);
    while (!pending.empty()) {
        const std::size_t u = pending.front();
        pending.pop();
        for (std::size_t v : out[u]) {
            if (!seen[v]) {
                seen[v] = 1;
                pending.push(v);
            }
        }
    }
    if (seen[t]) reject("sin esos tramos, s todavía llega a t");
    return 0;
}
