Problem p01146 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <climits>
#include <functional>
#include <iostream>
#include <queue>
#include <set>
#include <vector>

using namespace std;

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) for (int i = 0; i < (n); ++i)

struct Edge {
  int to;
  int cost;
};

struct Node {
  int city_index;
  int total_cost;
  int current_life;
  int remain_can_regain;

  bool operator>(const Node &a) const { return total_cost > a.total_cost; }
};

int main() {
  int city_count, initial_life, cooler_count, road_count, start_index,
      goal_index;
  while (cin >> city_count >> initial_life >> cooler_count >> road_count >>
             start_index >> goal_index,
         city_count) {
    // input
    vector<int> is_cooler(city_count, false);
    REP(i, cooler_count) {
      int cooler_index;
      cin >> cooler_index;
      is_cooler[cooler_index] = true;
    }
    vector<vector<Edge>> roads(city_count);
    REP(i, road_count) {
      int from, to, cost;
      cin >> from >> to >> cost;
      roads[from].push_back({to, cost});
      roads[to].push_back({from, cost});
    }

    // dijkstra
    vector<vector<int>> d(
        city_count,
        vector<int>(initial_life + 1,
                    INT_MAX)); // [city_index][current_life] => total_cost
    d[start_index][initial_life] = 0;
    priority_queue<Node, vector<Node>, greater<Node>> pq;
    pq.push({start_index, 0, initial_life, 0});
    while (true) {
      if (pq.empty()) {
        cout << "Help!" << endl;
        break;
      }
      auto current_node = pq.top();
      pq.pop();
      if (current_node.city_index == goal_index) {
        cout << current_node.total_cost << endl;
        break;
      }
      for (auto &road : roads[current_node.city_index]) {
        int total_cost = current_node.total_cost + road.cost;
        int life = current_node.current_life - road.cost;
        int remain_can_regain = is_cooler[current_node.city_index]
                                    ? initial_life - current_node.current_life
                                    : current_node.remain_can_regain;
        if (life < 0) {
          int shortage = -life;
          remain_can_regain -= shortage;
          if (remain_can_regain < 0) {
            continue;
          }
          total_cost += shortage;
          life = 0;
        }
        REP(i, remain_can_regain + 1) {
          auto &di = d[road.to][life + i];
          if (total_cost < di) {
            di = total_cost + i;
            pq.push({road.to, total_cost + i, life + i, remain_can_regain - i});
            break;
          }
        }
      }
    }
  }

  return 0;
}

Fixed submission:
#include <algorithm>
#include <climits>
#include <functional>
#include <iostream>
#include <queue>
#include <set>
#include <vector>

using namespace std;

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) for (int i = 0; i < (n); ++i)

struct Edge {
  int to;
  int cost;
};

struct Node {
  int city_index;
  int total_cost;
  int current_life;
  int remain_can_regain;

  bool operator>(const Node &a) const { return total_cost > a.total_cost; }
};

int main() {
  int city_count, initial_life, cooler_count, road_count, start_index,
      goal_index;
  while (cin >> city_count >> initial_life >> cooler_count >> road_count >>
             start_index >> goal_index,
         city_count) {
    // input
    vector<int> is_cooler(city_count, false);
    REP(i, cooler_count) {
      int cooler_index;
      cin >> cooler_index;
      is_cooler[cooler_index] = true;
    }
    vector<vector<Edge>> roads(city_count);
    REP(i, road_count) {
      int from, to, cost;
      cin >> from >> to >> cost;
      roads[from].push_back({to, cost});
      roads[to].push_back({from, cost});
    }

    // dijkstra
    vector<vector<int>> d(
        city_count,
        vector<int>(initial_life + 1,
                    INT_MAX)); // [city_index][current_life] => total_cost
    d[start_index][initial_life] = 0;
    priority_queue<Node, vector<Node>, greater<Node>> pq;
    pq.push({start_index, 0, initial_life, 0});
    while (true) {
      if (pq.empty()) {
        cout << "Help!" << endl;
        break;
      }
      auto current_node = pq.top();
      pq.pop();
      if (current_node.city_index == goal_index) {
        cout << current_node.total_cost << endl;
        break;
      }
      for (auto &road : roads[current_node.city_index]) {
        int total_cost = current_node.total_cost + road.cost;
        int life = current_node.current_life - road.cost;
        int remain_can_regain = is_cooler[current_node.city_index]
                                    ? initial_life - current_node.current_life
                                    : current_node.remain_can_regain;
        if (life < 0) {
          int shortage = -life;
          remain_can_regain -= shortage;
          if (remain_can_regain < 0) {
            continue;
          }
          total_cost += shortage;
          life = 0;
        }
        REP(i, remain_can_regain + 1) {
          auto &di = d[road.to][life + i];
          if (total_cost + i < di) {
            di = total_cost + i;
            pq.push({road.to, total_cost + i, life + i, remain_can_regain - i});
            break;
          }
        }
      }
    }
  }

  return 0;
}