Problem p00750 (C++) — buggy submission, verdict: Runtime Error

#include <algorithm>
#include <iostream>
#include <list>
#include <set>
#include <string>
#include <vector>

const std::string empty;
const std::string no("NO");

typedef int node_t;

struct arrow_t {
  node_t source;
  node_t sink;
  std::string label;
};

struct substring_t {
  std::string::const_iterator begin;
  std::string::const_iterator end;
  substring_t(const std::string &s) : begin(s.begin()), end(s.end()) {}
  int size() const { return end - begin; }
};

struct entry_t {
  substring_t label;
  std::set<node_t> nodes;
  entry_t(const substring_t &label) : label(label) {}
};

typedef std::list<entry_t> queue_t;

int compare(const substring_t &s1, const substring_t &s2) {
  for (std::string::const_iterator i1 = s1.begin, i2 = s2.begin;; ++i1, ++i2) {
    if (i1 == s1.end) {
      return i2 == s2.end ? 0 : -1;
    } else if (i2 == s2.end) {
      return 1;
    }
    int c = ((int)*i1) - ((int)*i2);
    if (c != 0) {
      return c < 0 ? -2 : 2;
    }
  }
  return 0;
}

queue_t::iterator insert(queue_t &queue, substring_t label) {
  for (queue_t::iterator it = queue.begin(); it != queue.end(); ++it) {
    switch (compare(it->label, label)) {
    case -2:
      return queue.end();
    case -1:
      label.begin += it->label.size();
      continue;
    case 0:
      return it;
    case 1:
      it->label.begin += label.size();
      return queue.insert(it, entry_t(label));
    case 2:
      return queue.insert(queue.erase(it, queue.end()), entry_t(label));
    }
  }
  return queue.insert(queue.end(), entry_t(label));
}

std::vector<bool> collect(int n, const std::vector<arrow_t> &arrows,
                          node_t goal) {
  std::vector<std::vector<node_t>> ins(n);
  for (const arrow_t &arrow : arrows) {
    ins[arrow.sink].push_back(arrow.source);
  }

  std::vector<bool> result(n);
  std::vector<node_t> stack;
  stack.push_back(goal);
  while (!stack.empty()) {
    node_t node = stack.back();
    stack.pop_back();

    result[node] = true;

    for (node_t source : ins[node]) {
      if (!result[source]) {
        stack.push_back(source);
      }
    }
  }
  return result;
}

std::string calc(int n, const std::vector<arrow_t> &arrows, node_t start,
                 node_t goal) {
  const std::vector<bool> &reachable_set = collect(n, arrows, goal);
  if (!reachable_set[start]) {
    return no;
  }

  size_t max = 0;
  std::vector<std::vector<const arrow_t *>> outs(n);
  for (const arrow_t &arrow : arrows) {
    if (reachable_set[arrow.sink]) {
      max = std::max(max, arrow.label.size());
      outs[arrow.source].push_back(&arrow);
    }
  }

  size_t limit = n * max;

  std::string result;
  queue_t queue;
  queue.push_back(entry_t(empty));
  queue.front().nodes.insert(start);
  while (true) {
    substring_t label = queue.front().label;
    std::set<node_t> nodes = queue.front().nodes;
    queue.pop_front();

    result.append(label.begin, label.end);
    if (nodes.find(goal) != nodes.end()) {
      return result;
    }
    if (result.size() > limit) {
      return no;
    }

    for (node_t node : nodes) {
      for (const arrow_t *arrow : outs[node]) {
        queue_t::iterator it = insert(queue, arrow->label);
        if (it != queue.end()) {
          it->nodes.insert(arrow->sink);
        }
      }
    }
  }
}

int main() {
  while (true) {
    int n, a, s, g;
    std::cin >> n >> a >> s >> g;
    if (n == 0) {
      break;
    }
    std::vector<arrow_t> arrows(a);
    for (arrow_t &arrow : arrows) {
      std::cin >> arrow.source >> arrow.sink >> arrow.label;
    }
    std::cout << calc(n, arrows, s, g) << std::endl;
  }
  return 0;
}

Error: 0

Fixed submission:

#include <algorithm>
#include <iostream>
#include <list>
#include <set>
#include <string>
#include <vector>

const std::string empty;
const std::string no("NO");

typedef int node_t;

struct arrow_t {
  node_t source;
  node_t sink;
  std::string label;
};

struct entry_t {
  std::string::const_iterator begin;
  std::string::const_iterator end;
  node_t node;
  entry_t(const std::string &label, node_t node)
      : begin(label.begin()), end(label.end()), node(node) {}
  int size() const { return end - begin; }
};

typedef std::list<entry_t> queue_t;

int compare(const entry_t &s1, const entry_t &s2) {
  for (std::string::const_iterator i1 = s1.begin, i2 = s2.begin;; ++i1, ++i2) {
    if (i1 == s1.end) {
      if (i2 == s2.end) {
        break;
      } else {
        return -1;
      }
    } else if (i2 == s2.end) {
      return 1;
    }
    if (*i1 < *i2) {
      return -2;
    } else if (*i1 > *i2) {
      return 2;
    }
  }
  if (s1.node < s2.node) {
    return -1;
  } else if (s1.node > s2.node) {
    return 1;
  } else {
    return 0;
  }
}

queue_t::iterator insert(queue_t &queue, entry_t entry) {
  for (queue_t::iterator it = queue.begin(); it != queue.end(); ++it) {
    switch (compare(*it, entry)) {
    case -2:
      return queue.end();
    case -1:
      entry.begin += it->size();
      continue;
    case 0:
      return it;
    case 1:
      it->begin += entry.size();
      return queue.insert(it, entry);
    case 2:
      return queue.insert(queue.erase(it, queue.end()), entry);
    }
  }
  return queue.insert(queue.end(), entry);
}

std::set<node_t> collect(int n, const std::vector<arrow_t> &arrows,
                         node_t goal) {
  std::vector<std::vector<node_t>> ins(n);
  for (const arrow_t &arrow : arrows) {
    ins[arrow.sink].push_back(arrow.source);
  }

  std::set<node_t> result;
  std::vector<node_t> stack;
  stack.push_back(goal);
  while (!stack.empty()) {
    node_t node = stack.back();
    stack.pop_back();

    result.insert(node);

    for (int source : ins[node]) {
      if (result.find(source) == result.end()) {
        stack.push_back(source);
      }
    }
  }
  return result;
}

std::string calc(int n, const std::vector<arrow_t> &arrows, node_t start,
                 node_t goal) {
  const std::set<node_t> &reachable_set = collect(n, arrows, goal);
  if (reachable_set.find(start) == reachable_set.end()) {
    return no;
  }

  size_t max = 0;
  std::vector<std::vector<entry_t>> outs(n);
  for (const arrow_t &arrow : arrows) {
    if (reachable_set.find(arrow.sink) != reachable_set.end()) {
      max = std::max(max, arrow.label.size());
      outs[arrow.source].push_back(entry_t(arrow.label, arrow.sink));
    }
  }

  size_t limit = n * max;

  std::string result;
  queue_t queue;
  queue.push_back(entry_t(empty, start));
  while (true) {
    entry_t entry = queue.front();
    queue.pop_front();

    result.append(entry.begin, entry.end);
    if (entry.node == goal) {
      return result;
    }
    if (result.size() > limit) {
      return no;
    }

    for (const entry_t &entry : outs[entry.node]) {
      insert(queue, entry);
    }
  }
}

int main() {
  while (true) {
    int n, a, s, g;
    std::cin >> n >> a >> s >> g;
    if (n == 0) {
      break;
    }
    std::vector<arrow_t> arrows(a);
    for (arrow_t &arrow : arrows) {
      std::cin >> arrow.source >> arrow.sink >> arrow.label;
    }
    std::cout << calc(n, arrows, s, g) << std::endl;
  }
  return 0;
}