Problem p03857 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
using namespace std;
typedef long long int ll;
const ll MOD(1e9 + 7);
const ll INF(2e9);
const int MAX_N(20001);

int par_road[MAX_N];
int rank_road[MAX_N];
int par_train[MAX_N];
int rank_train[MAX_N];

struct PARENT {
  int num; // num
           // 番目の都市は（問題上では1番目～n番目だが、0番目～n-1番目と表記することにする）
  int road; // 道に関するUnion-Find木でroad番目の都市を親に持ち
  int train; // 線路に関するUnion-Find木でtrain番目の都市を親に持つ
};

bool cmp(const PARENT a,
         const PARENT
             b) { // sort用関数　roadで昇順ソート、roadが等しかったらtrainで昇順
  if (a.road == b.road) {
    return a.train < b.train;
  } else {
    return a.road < b.road;
  }
}

void init(int n, int *par, int *rank) { // Unioo-Find木を生成
  for (int i = 0; i < n; i++) {
    par[i] = i;
    rank[i] = 0;
  }
}

int find(int x, int *par) { // 根探し
  if (par[x] == x) {
    return x;
  } else {
    return par[x] = find(par[x], par);
  }
}

void unite(int x, int y, int *par, int *rank) { // 連結
  x = find(x, par);
  y = find(y, par);
  if (x == y)
    return;

  if (rank[x] < rank[y]) {
    par[x] = y;
  } else {
    par[y] = x;
    if (rank[x] == rank[y]) {
      rank[x]++;
    }
  }
}

bool same(int x, int y, int *par) { // 根が等しいか判定
  return find(x, par) == find(y, par);
}

int main(void) {
  int n, k, l;
  cin >> n >> k >> l;

  init(n, par_road, rank_road);   // 道についてのUnion-Find木を生成
  init(n, par_train, rank_train); // 線路についてのUnion-Find木を生成
  int p, q, r, s;
  for (int i = 0; i < k; i++) { // 道の情報によって連結していく
    cin >> p >> q;
    unite(p - 1, q - 1, par_road,
          rank_road); // 0~n-1番目の道　としたので　p-1 q-1
  }
  for (int i = 0; i < l; i++) { // 線路の情報によって連結していく
    cin >> r >> s;
    unite(r - 1, s - 1, par_train, rank_train);
  }

  PARENT *parent = new PARENT[n];
  for (
      int i = 0; i < n;
      i++) { // num番目の都市は　road番目の都市を道根に持ち、train番目の都市を線路根に持つ
    parent[i].num = i;
    parent[i].road = find(i, par_road);
    parent[i].train = find(i, par_train);
  }

  sort(parent, parent + n, cmp);

  int *answer = new int[n];
  int memo_start = 0, count = 1;
  int i;

  for (i = 1; i < n; i++) {
    if (parent[i].road == parent[i - 1].road &&
        parent[i].train == parent[i - 1].train) {
      count++;
    } else {
      for (memo_start; memo_start < i;
           memo_start++) { // memo_startは現在の位置を指して終わる
        answer[(parent[memo_start]).num] = count;
      }
      count = 1;
    }
  }

  for (memo_start; memo_start < i; memo_start++) {
    answer[parent[memo_start].num] = count;
  }

  for (int i = 0; i < n; i++) {
    cout << answer[i] << " ";
  }
  cout << endl;

  return 0;
}

Fixed submission:
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
using namespace std;
typedef long long int ll;
const ll MOD(1e9 + 7);
const ll INF(2e9);
const int MAX_N(200001);

int par_road[MAX_N];
int rank_road[MAX_N];
int par_train[MAX_N];
int rank_train[MAX_N];

struct PARENT {
  int num; // num
           // 番目の都市は（問題上では1番目～n番目だが、0番目～n-1番目と表記することにする）
  int road; // 道に関するUnion-Find木でroad番目の都市を親に持ち
  int train; // 線路に関するUnion-Find木でtrain番目の都市を親に持つ
};

bool cmp(const PARENT a,
         const PARENT
             b) { // sort用関数　roadで昇順ソート、roadが等しかったらtrainで昇順
  if (a.road == b.road) {
    return a.train < b.train;
  } else {
    return a.road < b.road;
  }
}

void init(int n, int *par, int *rank) { // Unioo-Find木を生成
  for (int i = 0; i < n; i++) {
    par[i] = i;
    rank[i] = 0;
  }
}

int find(int x, int *par) { // 根探し
  if (par[x] == x) {
    return x;
  } else {
    return par[x] = find(par[x], par);
  }
}

void unite(int x, int y, int *par, int *rank) { // 連結
  x = find(x, par);
  y = find(y, par);
  if (x == y)
    return;

  if (rank[x] < rank[y]) {
    par[x] = y;
  } else {
    par[y] = x;
    if (rank[x] == rank[y]) {
      rank[x]++;
    }
  }
}

bool same(int x, int y, int *par) { // 根が等しいか判定
  return find(x, par) == find(y, par);
}

int main(void) {
  int n, k, l;
  cin >> n >> k >> l;

  init(n, par_road, rank_road);   // 道についてのUnion-Find木を生成
  init(n, par_train, rank_train); // 線路についてのUnion-Find木を生成
  int p, q, r, s;
  for (int i = 0; i < k; i++) { // 道の情報によって連結していく
    cin >> p >> q;
    unite(p - 1, q - 1, par_road,
          rank_road); // 0~n-1番目の道　としたので　p-1 q-1
  }
  for (int i = 0; i < l; i++) { // 線路の情報によって連結していく
    cin >> r >> s;
    unite(r - 1, s - 1, par_train, rank_train);
  }

  PARENT *parent = new PARENT[n];
  for (
      int i = 0; i < n;
      i++) { // num番目の都市は　road番目の都市を道根に持ち、train番目の都市を線路根に持つ
    parent[i].num = i;
    parent[i].road = find(i, par_road);
    parent[i].train = find(i, par_train);
  }

  sort(parent, parent + n, cmp);

  int *answer = new int[n];
  int memo_start = 0, count = 1;
  int i;

  for (i = 1; i < n; i++) {
    if (parent[i].road == parent[i - 1].road &&
        parent[i].train == parent[i - 1].train) {
      count++;
    } else {
      for (memo_start; memo_start < i;
           memo_start++) { // memo_startは現在の位置を指して終わる
        answer[(parent[memo_start]).num] = count;
      }
      count = 1;
    }
  }

  for (memo_start; memo_start < i; memo_start++) {
    answer[parent[memo_start].num] = count;
  }

  for (int i = 0; i < n; i++) {
    cout << answer[i] << " ";
  }
  cout << endl;

  return 0;
}