Cod sursa(job #1554932)

Utilizator bolovMihail Balan bolov Data 21 decembrie 2015 22:58:50
Problema Stramosi Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.12 kb
/* Bălan Mihail
 * http://www.infoarena.ro/problema/stramosi
 */

#include <cstdlib>

#include <iostream>
#include <fstream>
#include <utility>
#include <vector>
#include <algorithm>
#include <string>
#include <tuple>

using std::cin;
using std::cout;
using std::cerr;
using std::endl;

namespace bolov {
namespace utils {

// inserts val into the sorted container, maintaining the sorted property
template <class Container, class Compare>
static auto insert_sorted(Container &container,
                          typename Container::value_type const &val,
                          Compare &&comp) -> void {
  container.insert(std::upper_bound(std::begin(container), std::end(container),
                                    val, std::forward<Compare>(comp)),
                   val);
}

} // ns utils

namespace stramos {

struct Question {
  int order;
  int member;
  int ancestor_distance;
  int ancestor;
};

static auto read(std::string const &file_name)
    -> std::tuple<std::vector<int>, std::vector<Question>> {
  std::ifstream ifs{file_name};

  if (!ifs) {
    throw std::runtime_error{"unable to open file"};
  }

  auto num_members = int{}, num_questions = int{};

  ifs >> num_members >> num_questions;


  auto parents = std::vector<int>{0};
  parents.reserve(num_members + 1);
  for (auto i = 1; i <= num_members; ++i) {
    auto ancestor = int{};
    ifs >> ancestor;
    parents.push_back(ancestor);
  }

  auto questions = std::vector<Question>{};
  questions.reserve(num_questions);
  for (auto i = 0; i < num_questions; ++i) {
    auto member = int{};
    auto order = int{};
    ifs >> member >> order;

    // keep sorted by distance first and then by member
    utils::insert_sorted(questions, {i, member, order, -1},
                         [](Question const &lhs, Question const &rhs) -> bool {
      return lhs.ancestor_distance < rhs.ancestor_distance ||
             (lhs.ancestor_distance == rhs.ancestor_distance &&
              lhs.member < rhs.member);
    });
  }

  return std::make_tuple(std::move(parents), std::move(questions));
}

static auto write(std::string const &file_name,
                  std::vector<Question> &questions) -> void {
  // sort by orginal order
  std::sort(std::begin(questions), std::end(questions),
            [](bolov::stramos::Question const &lhs,
               bolov::stramos::Question const &rhs) {
    return lhs.order < rhs.order;
  });

  std::ofstream ofs{file_name};
  for (auto const &question : questions) {
    ofs << question.ancestor << endl;
  }
}

using question_iterator = typename std::vector<Question>::iterator;

// answers all questions with <distance>
// ancestors contains ancestors of distance <distance>
static auto answer_and_advance_question_it(std::vector<int> const &ancestors,
                                           int distance,
                                           question_iterator &first,
                                           question_iterator last) -> bool {
  for (; first != last && first->ancestor_distance == distance; ++first) {
    first->ancestor = ancestors[first->member];
  }
  return first != last;
}

static auto compute_next_distance(std::vector<int> const &parents,
                                  std::vector<int> &ancestors) -> void {
  auto size = static_cast<int>(parents.size());

  for (auto i = 1; i < size; ++i) {
    ancestors[i] = parents[ancestors[i]];
  }
}

static auto answer(std::vector<int> &parents,
                   std::vector<Question> &questions) -> void {

  auto question_it = std::begin(questions);
  auto const question_last = std::end(questions);

  auto ancestors = parents;

  for (auto distance = 1;; ++distance) {
    if (!answer_and_advance_question_it(ancestors, distance, question_it,
                                        question_last))
      return;

    compute_next_distance(parents, ancestors);
  }
}

} // ns stramos
} // ns bolov

auto main() -> int {
  auto parents = std::vector<int>{};
  auto questions = std::vector<bolov::stramos::Question>{};

  std::tie(parents, questions) = bolov::stramos::read("stramosi.in");

  bolov::stramos::answer(parents, questions);

  bolov::stramos::write("stramosi.out", questions);

  return 0;
}