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

#include <iostream>
#include <queue>
#include <tuple>

using namespace std;

struct Node {
  // ダイクストラ法のためのデータ
  bool done; // 確定ノードか否か
  int cost; // このノードへの現時点で判明している最小コスト
};

const int S[4][2] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
Node m[502][502];
int N;
int P[502][502] = {0};
int Q[502 * 502] = {0};

int diff_solve(int num, int sx, int sy) {
  // 周辺を差分更新
  priority_queue<tuple<int, int, int>> que;
  que.push(make_tuple(-m[sx][sy].cost, sx, sy));
  while (!que.empty()) {
    auto next = que.top();
    que.pop();
    int c(-get<0>(next)), cx(get<1>(next)), cy(get<2>(next));

    for (int d = 0; d < 4; d++) {
      int x = cx + S[d][0];
      int y = cy + S[d][1];
      int cost = c + (num < P[cx][cy] ? 1 : 0);

      if (cost < m[x][y].cost) {
        m[x][y].cost = cost;
        auto t = make_tuple(-cost, x, y);
        que.push(t);
      }
    }
  }

  return m[sx][sy].cost;
}

int main() {
  cin >> N;
  for (int i = 1; i <= N * N; i++) {
    int pos;
    cin >> pos;
    P[(pos - 1) / N + 1][(pos - 1) % N + 1] = i;
    Q[i] = pos;
  }

  /*cerr << "player" << endl;
  for (int i = 0; i <= N + 1; i++)
  {
    for (int j = 0; j <= N + 1; j++) cerr << " " << P[i][j];
    cerr << endl;
  }*/

  // 初期化
  for (int i = 0; i <= N + 1; i++)
    for (int j = 0; j <= N + 1; j++) {
      m[i][j].cost = max(0, min(min(i - 1, N - i), min(j - 1, N - j)));
      m[i][j].done = false;
    }

  int sum = 0;
  for (int i = 1; i <= N * N; i++) {
    int pos = Q[i];
    // int cost = solve(i, (pos - 1) / N + 1, (pos - 1) % N + 1);
    int cost = diff_solve(i, (pos - 1) / N + 1, (pos - 1) % N + 1);

    /*cerr << "cost" << endl;
    for (int i = 1; i <= N; i++)
    {
      for (int j = 1; j <= N; j++) cerr << " " << m[i][j].cost;
      cerr << endl;
    }*/

    sum += cost;
  }

  cout << sum << endl;
}


Error: TLE

Fixed submission:

#include <iostream>
#include <queue>
#include <tuple>

using namespace std;

struct Node {
  // ダイクストラ法のためのデータ
  bool done; // 確定ノードか否か
  int cost; // このノードへの現時点で判明している最小コスト
};

const int S[4][2] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
Node m[502][502];
int N;
int P[502][502] = {0};
int Q[502 * 502] = {0};

int solve(int num, int sx, int sy) {
  for (int i = 1; i <= N; i++)
    for (int j = 1; j <= N; j++) {
      m[i][j].cost = 100000000;
      m[i][j].done = false;
    }
  priority_queue<tuple<int, int, int>> que;
  m[sx][sy].cost = 0;
  m[sx][sy].done = true;
  que.push(make_tuple(-0, sx, sy));

  while (!que.empty()) {
    auto next = que.top();
    que.pop();

    int c(-get<0>(next)), cx(get<1>(next)), cy(get<2>(next));

    // cerr << "xy " << cx << " " << cy << endl;

    for (int d = 0; d < 4; d++) {
      int x = cx + S[d][0];
      int y = cy + S[d][1];
      if (P[x][y] == 0 || m[x][y].done)
        continue;
      // cerr << " try " << x << " " << y << endl;
      int cost = c + (num < P[x][y] ? 1 : 0);

      m[x][y].cost = cost;
      m[x][y].done = true;
      auto t = make_tuple(-cost, x, y);
      que.push(t);
    }
  }

  /*cerr << "cost" << endl;
  for (int i = 1; i <= N; i++)
  {
    for (int j = 1; j <= N; j++) cerr << " " << m[i][j].cost;
    cerr << endl;
  }*/

  int mcost = 100000000;
  for (int i = 1; i <= N; i++) {
    mcost = min(mcost, m[1][i].cost);
    mcost = min(mcost, m[N][i].cost);
    mcost = min(mcost, m[i][1].cost);
    mcost = min(mcost, m[i][N].cost);
  }
  return mcost;
}

int main() {
  cin >> N;
  for (int i = 1; i <= N * N; i++) {
    int pos;
    cin >> pos;
    P[(pos - 1) / N + 1][(pos - 1) % N + 1] = i;
    Q[i] = pos;
  }

  /*cerr << "player" << endl;
  for (int i = 0; i <= N + 1; i++)
  {
    for (int j = 0; j <= N + 1; j++) cerr << " " << P[i][j];
    cerr << endl;
  }*/

  int sum = 0;
  for (int i = 1; i <= N * N; i++) {
    int pos = Q[i];
    int cost = solve(i, (pos - 1) / N + 1, (pos - 1) % N + 1);
    sum += cost;
  }

  cout << sum << endl;
}