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

#include <algorithm>
#include <cassert>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <deque>
#include <iostream>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#define REP(i, s, n) for (int i = s; i < n; ++i)
#define rep(i, n) REP(i, 0, n)

using namespace std;

string tree_to_string(vector<vector<int>> &tree, int cur, int prev) {
  vector<string> vec;
  rep(i, (int)tree[cur].size()) {
    if (tree[cur][i] == prev)
      continue;
    vec.push_back(tree_to_string(tree, tree[cur][i], cur));
  }
  if (vec.empty())
    return "()";
  sort(vec.begin(), vec.end());
  string ret = "(";
  rep(i, (int)vec.size()) { ret += vec[i]; }
  ret += ")";
  return ret;
}

bool rootedTreeIsomorphism(vector<vector<int>> &t1, int root1,
                           vector<vector<int>> &t2, int root2) {
  return tree_to_string(t1, root1, -1) == tree_to_string(t2, root2, -1);
}

int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};

struct UnionFind {
  int par[100100];
  UnionFind(int size = 100100) { rep(i, size) par[i] = i; }
  int find(int x) {
    assert(x < 100100);
    if (x == par[x])
      return x;
    return par[x] = find(par[x]);
  }
  void unit(int x, int y) {
    x = find(x), y = find(y);
    if (x != y)
      par[x] = y;
  }
};

struct Picture {
  int h, w;
  vector<string> p;
  bool modified;

  Picture(int h = 0, int w = 0, vector<string> p = vector<string>())
      : h(h), w(w), p(p), modified(false) {}

  bool isValid(int x, int y) { return 0 <= x && x < w && 0 <= y && y < h; }

  void modify() {
    if (modified) {
      cerr << "already modified" << endl;
      return;
    }
    modified = true;
    vector<string> new_p(h + 2, string(w + 2, '.'));
    rep(i, h) {
      rep(j, w) { new_p[i + 1][j + 1] = p[i][j]; }
    }
    p = new_p;
    h += 2;
    w += 2;
  }

  void print() { rep(i, h) cout << p[i] << endl; }

  vector<vector<int>> to_tree() {
    UnionFind uf(h * w);
    rep(i, h) rep(j, w) {
      if (p[i][j] == '.') {
        rep(k, 4) {
          int nx = j + dx[k];
          int ny = i + dy[k];
          if (!isValid(nx, ny))
            continue;
          if (p[ny][nx] != '.')
            continue;
          uf.unit(j + i * w, nx + ny * w);
        }
      } else {
        REP(dy_b, -1, 2) REP(dx_b, -1, 2) {
          if (dx_b == 0 && dy_b == 0)
            continue;
          int nx = j + dx_b;
          int ny = i + dy_b;
          if (!isValid(nx, ny))
            continue;
          if (p[ny][nx] != '#')
            continue;
          uf.unit(j + i * w, nx + ny * w);
        }
      }
    }

    vector<bool> used(h * w, false);

    map<int, int> toIndex;
    int idx = 0;
    rep(i, h) rep(j, w) {
      if (!toIndex.count(uf.find(j + i * w))) {
        toIndex[uf.find(j + i * w)] = idx++;
      }
    }
    vector<vector<int>> tree(idx, vector<int>());

    rep(i, h) rep(j, w) {
      int cur = uf.find(j + i * w);
      if (used[cur])
        continue;
      assert(toIndex.count(cur));
      int s = toIndex[cur];
      rep(k, h) rep(l, w) {
        int next = uf.find(l + k * w);
        if (next != cur)
          continue;
        REP(dy_1, -1, 2) REP(dx_1, -1, 2) {
          if (dx_1 == 0 && dy_1 == 0)
            continue;
          int nx = l + dx_1;
          int ny = k + dy_1;
          if (!isValid(nx, ny))
            continue;
          if (p[ny][nx] == p[i][j])
            continue;
          int id = uf.find(nx + ny * w);
          if (used[id])
            continue;
          assert(toIndex.count(id));
          int t = toIndex[id];
          if (s == t)
            continue;
          tree[s].push_back(t);
        }
      }
      used[cur] = true;
    }

    rep(i, idx) {
      sort(tree[i].begin(), tree[i].end());
      tree[i].erase(unique(tree[i].begin(), tree[i].end()), tree[i].end());
    }

    return tree;
  }
};

void compute(Picture *picts) {
  rep(i, 2) picts[i].modify();

  vector<vector<int>> tree1 = picts[0].to_tree();
  vector<vector<int>> tree2 = picts[1].to_tree();

  cout << (rootedTreeIsomorphism(tree1, 0, tree2, 0) ? "yes" : "no") << endl;
}

int main() {
  while (1) {
    Picture picts[2];
    rep(i, 2) {
      cin >> picts[i].h >> picts[i].w;
      if (i == 0 && picts[i].h == 0 && picts[i].w == 0)
        goto Fin;
      picts[i].p.resize(picts[i].h);
      rep(j, picts[i].h) cin >> picts[i].p[j];
    }
    compute(picts);
  }
Fin:
  return 0;
}

Error: 0

Fixed submission:

#include <algorithm>
#include <cassert>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <deque>
#include <iostream>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#define REP(i, s, n) for (int i = s; i < n; ++i)
#define rep(i, n) REP(i, 0, n)

using namespace std;

//

typedef vector<int> vi;
typedef vector<vi> vvi;

vvi children, subtreeLabels, tree, L;
vi pred, mp; // mp ??????????????????
int n;

bool compare(int a, int b) { return subtreeLabels[a] < subtreeLabels[b]; }

bool equals(int a, int b) { return subtreeLabels[a] == subtreeLabels[b]; }

void generateMapping(int r1, int r2) {
  mp.resize(n);
  mp[r1] = r2 - n;
  sort(children[r1].begin(), children[r1].end(), compare);
  sort(children[r2].begin(), children[r2].end(), compare);
  for (int i = 0; i < (int)children[r1].size(); i++) {
    int u = children[r1][i];
    int v = children[r2][i];
    generateMapping(u, v);
  }
}

vi findCenter(int offset = 0) {
  int cnt = n;
  vi a;
  vi deg(n);
  for (int i = 0; i < n; i++) {
    deg[i] = tree[i + offset].size();
    if (deg[i] <= 1) {
      a.push_back(i + offset);
      --cnt;
    }
  }
  while (cnt > 0) {
    vi na;
    for (int i = 0; i < (int)a.size(); i++) {
      int u = a[i];
      for (int j = 0; j < (int)tree[u].size(); j++) {
        int v = tree[u][j];
        if (--deg[v - offset] == 1) {
          na.push_back(v);
          --cnt;
        }
      }
    }
    a = na;
  }
  return a;
}

int dfs(int u, int p = -1, int depth = 0) {
  L[depth].push_back(u);
  int h = 0;
  for (int i = 0; i < (int)tree[u].size(); i++) {
    int v = tree[u][i];
    if (v == p)
      continue;
    pred[v] = u;
    children[u].push_back(v);
    h = max(h, dfs(v, u, depth + 1));
  }
  return h + 1;
}

bool rootedTreeIsomorphism(int r1, int r2) {
  L.assign(n, vi());
  pred.assign(2 * n, -1);
  children.assign(2 * n, vi());

  int h1 = dfs(r1);
  int h2 = dfs(r2);
  if (h1 != h2)
    return false;

  int h = h1 - 1;
  vi label(2 * n);
  subtreeLabels.assign(2 * n, vi());

  for (int i = h - 1; i >= 0; i--) {
    for (int j = 0; j < (int)L[i + 1].size(); j++) {
      int v = L[i + 1][j];
      subtreeLabels[pred[v]].push_back(label[v]);
    }
    for (int j = 0; j < (int)L[i].size(); j++) {
      int v = L[i][j];
      sort(subtreeLabels[v].begin(), subtreeLabels[v].end());
    }

    sort(L[i].begin(), L[i].end(), compare);

    for (int j = 0, cnt = 0; j < (int)L[i].size(); j++) {
      if (j && !equals(L[i][j], L[i][j - 1]))
        ++cnt;
      label[L[i][j]] = cnt;
    }
  }

  if (!equals(r1, r2))
    return false;

  generateMapping(r1, r2);
  return true;
}

bool treeIsomorphism(vector<vector<int>> &t1, vector<vector<int>> &t2) {
  if (t1.size() != t2.size())
    return false;
  n = t1.size();

  tree.assign(2 * n, vi());

  rep(u, n) {
    rep(i, (int)t1[u].size()) {
      int v = t1[u][i];
      tree[u].push_back(v);
    }
    rep(i, (int)t2[u].size()) {
      int v = t2[u][i];
      tree[u + n].push_back(v + n);
    }
  }

  vi c1 = findCenter();
  vi c2 = findCenter(n);
  if (c1.size() == c2.size()) {
    if (rootedTreeIsomorphism(c1[0], c2[0]))
      return true;
    else if (c1.size() > 1)
      return rootedTreeIsomorphism(c1[1], c2[0]);
  }
  return false;
}

//

int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};

struct UnionFind {
  int par[10010];
  UnionFind(int size = 10010) { rep(i, size) par[i] = i; }
  int find(int x) {
    assert(x < 10010);
    if (x == par[x])
      return x;
    return par[x] = find(par[x]);
  }
  void unit(int x, int y) {
    x = find(x), y = find(y);
    if (x != y)
      par[x] = y;
  }
};

struct Picture {
  int h, w;
  vector<string> p;
  bool modified;

  Picture(int h = 0, int w = 0, vector<string> p = vector<string>())
      : h(h), w(w), p(p), modified(false) {}

  bool isValid(int x, int y) { return 0 <= x && x < w && 0 <= y && y < h; }

  void modify() {
    if (modified) {
      cerr << "already modified" << endl;
      return;
    }
    modified = true;
    vector<string> new_p(h + 2, string(w + 2, '.'));
    rep(i, h) {
      rep(j, w) { new_p[i + 1][j + 1] = p[i][j]; }
    }
    p = new_p;
    h += 2;
    w += 2;
  }

  void print() { rep(i, h) cout << p[i] << endl; }

  vector<vector<int>> to_tree() {
    UnionFind uf(h * w);
    rep(i, h) rep(j, w) {
      if (p[i][j] == '.') {
        rep(k, 4) {
          int nx = j + dx[k];
          int ny = i + dy[k];
          if (!isValid(nx, ny))
            continue;
          if (p[ny][nx] != '.')
            continue;
          uf.unit(j + i * w, nx + ny * w);
        }
      } else {
        REP(dy_b, -1, 2) REP(dx_b, -1, 2) {
          if (dx_b == 0 && dy_b == 0)
            continue;
          int nx = j + dx_b;
          int ny = i + dy_b;
          if (!isValid(nx, ny))
            continue;
          if (p[ny][nx] != '#')
            continue;
          uf.unit(j + i * w, nx + ny * w);
        }
      }
    }

    vector<bool> used(h * w, false);

    map<int, int> toIndex;
    int idx = 0;
    rep(i, h) rep(j, w) {
      if (!toIndex.count(uf.find(j + i * w))) {
        toIndex[uf.find(j + i * w)] = idx++;
      }
    }
    vector<vector<int>> tree(idx, vector<int>());

    rep(i, h) rep(j, w) {
      int cur = uf.find(j + i * w);
      if (used[cur])
        continue;
      assert(toIndex.count(cur));
      int s = toIndex[cur];
      rep(k, h) rep(l, w) {
        int next = uf.find(l + k * w);
        if (next != cur)
          continue;
        REP(dy_1, -1, 2) REP(dx_1, -1, 2) {
          if (dx_1 == 0 && dy_1 == 0)
            continue;
          int nx = l + dx_1;
          int ny = k + dy_1;
          if (!isValid(nx, ny))
            continue;
          if (p[ny][nx] == p[i][j])
            continue;
          int id = uf.find(nx + ny * w);
          if (used[id])
            continue;
          assert(toIndex.count(id));
          int t = toIndex[id];
          if (s == t)
            continue;
          tree[s].push_back(t);
          tree[t].push_back(s);
        }
      }
      used[cur] = true;
    }

    rep(i, idx) {
      sort(tree[i].begin(), tree[i].end());
      tree[i].erase(unique(tree[i].begin(), tree[i].end()), tree[i].end());
    }

    return tree;
  }
};

void compute(Picture *picts) {
  /*
  puts("");
  cout << "before---" << endl;
  rep(i,2) {
    picts[i].print();
    puts("");
  }
  */
  // cout << "after---" << endl;
  rep(i, 2) picts[i].modify();
  /*
  rep(i,2) {
    picts[i].print();
    puts("");
  }
  */

  vector<vector<int>> tree1 = picts[0].to_tree();
  // puts("-----");
  vector<vector<int>> tree2 = picts[1].to_tree();
  /*
  rep(i,(int)tree1.size()) {
    cout << i << "-th node" << endl;
    rep(j,(int)tree1[i].size()) {
      cout << tree1[i][j] << " ";
    } puts("");
  }
  puts("^^^");

  rep(i,(int)tree1.size()) {
    cout << i << "-th node" << endl;
    rep(j,(int)tree1[i].size()) {
      cout << tree1[i][j] << " ";
    } puts("");
  }
  */

  cout << (treeIsomorphism(tree1, tree2) ? "yes" : "no") << endl;
}

int main() {
  while (1) {
    Picture picts[2];
    rep(i, 2) {
      cin >> picts[i].h >> picts[i].w;
      if (i == 0 && picts[i].h == 0 && picts[i].w == 0)
        goto Fin;
      picts[i].p.resize(picts[i].h);
      rep(j, picts[i].h) cin >> picts[i].p[j];
    }
    compute(picts);
  }
Fin:
  return 0;
}