Problem p02703 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 1000000007
/* ちゃんと考えてわかって実装 */

const int MAX_V = 50;
const int MAX_S = 50 * MAX_V + 5;
const ll INF = 1e18;

struct Edge {
  int to, a, b;
  // これを書いたらerrorが取れた。どうして必要なのｫぉ
  Edge(int to, int a, int b) : to(to), a(a), b(b) {}
};

struct State {
  int v, s; // state = (頂点, 所持金)
  ll x;     // その状態までの経過時間

  // これを書いたらerrorが取れた。どうして必要なのｫぉ
  State(int v, int s, ll x) : v(v), s(s), x(x) {}

  bool operator<(const State &a) const {
    return x > a.x; // (x < a.x だとちゃんと動かねぇ)
  }
};

vector<Edge> g[MAX_V]; // 各頂点から伸びている辺の集合として保持。
ll min_time[MAX_V][MAX_S + 5]; // 状態(v, s)までの最小の時間を記録。

int main(void) {
  int n, m, s;
  cin >> n >> m >> s;

  for (int i = 0; i < m; i++) {
    int u, v, a, b;
    cin >> u >> v >> a >> b;
    u--;
    v--;
    g[u].emplace_back(v, a, b);
    g[v].emplace_back(u, a, b);
  }

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < MAX_S + 5; j++) {
      min_time[i][j] = INF;
      // たどり着けない状態はINFのまま。
      // 以下では、たどり着ける状態についてその時間の最小値を探索する。
    }
  }

  vector<int> c(n), d(n);
  for (int i = 0; i < n; i++) {
    cin >> c[i] >> d[i];
  }

  s = min(s, MAX_S); // 十分な値で切り捨てる。
  priority_queue<State> pq;

  // pqに状態(v, s, x)を emplace するときに、
  // min_time[v][s]の値を x に更新する。(xが最小じゃないなら更新しない。)
  auto push = [&](int v, int s, ll x) {
    if (s < 0)
      return;
    if (min_time[v][s] <= x)
      return;
    min_time[v][s] = x;
    pq.emplace(v, s, x);
  };

  // 初期状態は(0, s, 0)
  push(0, s, 0);
  while (!pq.empty()) {
    State now = pq.top();
    pq.pop();
    int v = now.v, s = now.s;
    ll x = now.x;

    // if(min_time[v][s] != x) continue; // なぜ?????(消しても通る)

    // 遷移その1 : 換金
    int next_s = min(s + c[v], MAX_S);
    push(v, next_s, x + d[v]);

    // 遷移その2 : 電車に乗る
    // そこから伸びている辺を全てみる
    for (Edge e : g[v]) {
      push(e.to, s - e.a, x + e.b);
    }
  }

  // 答えの出力(min_timeのなかにある)
  for (int i = 1; i < n; i++) {
    ll ans = INF;
    for (int j = 0; j < MAX_S + 5; j++) {
      ans = min(ans, min_time[i][j]);
    }
    cout << ans << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 1000000007
/* ちゃんと考えてわかって実装 */

const int MAX_V = 50;
const int MAX_S = 50 * MAX_V + 5;
const ll INF = 1e18;

struct Edge {
  int to, a, b;
  // これを書いたらerrorが取れた。どうして必要なのｫぉ
  Edge(int to, int a, int b) : to(to), a(a), b(b) {}
};

struct State {
  int v, s; // state = (頂点, 所持金)
  ll x;     // その状態までの経過時間

  // これを書いたらerrorが取れた。どうして必要なのｫぉ
  State(int v, int s, ll x) : v(v), s(s), x(x) {}

  bool operator<(const State &a) const {
    return x < a.x; // (x < a.x だとちゃんと動かねぇ)
  }
};

vector<Edge> g[MAX_V]; // 各頂点から伸びている辺の集合として保持。
ll min_time[MAX_V][MAX_S + 5]; // 状態(v, s)までの最小の時間を記録。

int main(void) {
  int n, m, s;
  cin >> n >> m >> s;

  for (int i = 0; i < m; i++) {
    int u, v, a, b;
    cin >> u >> v >> a >> b;
    u--;
    v--;
    g[u].emplace_back(v, a, b);
    g[v].emplace_back(u, a, b);
  }

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < MAX_S + 5; j++) {
      min_time[i][j] = INF;
      // たどり着けない状態はINFのまま。
      // 以下では、たどり着ける状態についてその時間の最小値を探索する。
    }
  }

  vector<int> c(n), d(n);
  for (int i = 0; i < n; i++) {
    cin >> c[i] >> d[i];
  }

  s = min(s, MAX_S); // 十分な値で切り捨てる。
  priority_queue<State> pq;

  // pqに状態(v, s, x)を emplace するときに、
  // min_time[v][s]の値を x に更新する。(xが最小じゃないなら更新しない。)
  auto push = [&](int v, int s, ll x) {
    if (s < 0)
      return;
    if (min_time[v][s] <= x)
      return;
    min_time[v][s] = x;
    pq.emplace(v, s, x);
  };

  // 初期状態は(0, s, 0)
  push(0, s, 0);
  while (!pq.empty()) {
    State now = pq.top();
    pq.pop();
    int v = now.v, s = now.s;
    ll x = now.x;

    // if(min_time[v][s] != x) continue; // なぜ?????(消しても通る)

    // 遷移その1 : 換金
    int next_s = min(s + c[v], MAX_S);
    push(v, next_s, x + d[v]);

    // 遷移その2 : 電車に乗る
    // そこから伸びている辺を全てみる
    for (Edge e : g[v]) {
      push(e.to, s - e.a, x + e.b);
    }
  }

  // 答えの出力(min_timeのなかにある)
  for (int i = 1; i < n; i++) {
    ll ans = INF;
    for (int j = 0; j < MAX_S + 5; j++) {
      ans = min(ans, min_time[i][j]);
    }
    cout << ans << endl;
  }
  return 0;
}