// Verificador de "La reunión de la empresa, con la lista": verificador ENTRADA ESPERADA SALIDA.
// En ESPERADA está solo el mayor aporte. Aquí se comprueba que la salida diga ese total, y que su
// lista sea una reunión válida que suma eso. Termina con 0 si todo está bien, y con 1 y un mensaje si no.
#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <iostream>
#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: signo opcional y a lo sumo 17 dígitos,
// que alcanzan para el mayor total posible, 10^15.
bool parse_number(const std::string& word, long long& value) {
    std::size_t start = word[0] == '-' ? 1 : 0;
    if (word.size() == start || word.size() - start > 17) return false;
    value = 0;
    for (std::size_t i = start; i < word.size(); i++) {
        if (word[i] < '0' || word[i] > '9') return false;
        value = value * 10 + (word[i] - '0');
    }
    if (start == 1) value = -value;
    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]);

    long long n = 0;
    input >> n;
    std::vector<long long> value(static_cast<std::size_t>(n) + 1, 0);
    std::vector<long long> boss(static_cast<std::size_t>(n) + 1, 0);
    for (long long i = 1; i <= n; i++) input >> value[i] >> boss[i];

    long long best = 0;
    expected >> best;

    std::string word;
    long long claimed = 0;
    if (!(output >> word) || !parse_number(word, claimed)) reject("la primera palabra no es un número");
    if (claimed != best) reject("mayor aporte esperado: " + std::to_string(best) + ", salió " + word);

    long long count = 0;
    if (!(output >> word) || !parse_number(word, count)) reject("falta k, o no es un número");
    if (count < 0 || count > n) reject("k fuera de rango: " + word);

    std::vector<char> inside(static_cast<std::size_t>(n) + 1, 0);
    long long total = 0;
    for (long long t = 0; t < count; t++) {
        long long person = 0;
        if (!(output >> word)) reject("faltan personas en la lista");
        if (!parse_number(word, person)) reject("número inválido: " + word);
        if (person < 1 || person > n) reject("persona fuera de rango: " + word);
        if (inside[person]) reject("persona repetida: " + word);
        inside[person] = 1;
        total += value[person];
    }
    if (output >> word) reject("sobra texto después de la lista: " + word);

    for (long long i = 1; i <= n; i++) {
        if (inside[i] && inside[boss[i]]) {
            reject("la persona " + std::to_string(i) + " va junto con su jefe directo, " + std::to_string(boss[i]));
        }
    }
    if (total != best) reject("la lista suma " + std::to_string(total) + ", y debería sumar " + std::to_string(best));
    return 0;
}
