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

#include <bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 600001

int N = 1;
int euler_index, root;
int num_count[NUM][10], change_table[NUM][10];
int LEFT[100000], RIGHT[100000];
vector<int> G[100000];

void init(int first_N) {
  while (N < first_N)
    N *= 2;
}

// 最初、全ての電球の明るさは0
void add(int loc) {
  loc += N - 1;

  num_count[loc][0] += 1;

  while (loc > 0) {
    loc = (loc - 1) / 2;
    num_count[loc][0] = num_count[2 * loc + 1][0] + num_count[2 * loc + 2][0];
  }
}

void update_array(int node_id, int next_array[10]) {

  int next_count[10];
  for (int i = 0; i <= 9; i++)
    next_count[i] = 0;

  for (int i = 0; i <= 9; i++) {
    next_count[next_array[i]] += num_count[node_id][i];
  }
  int next_change_table[10];
  for (int i = 0; i <= 9; i++) {
    next_change_table[i] = next_array[change_table[node_id][i]];
  }

  for (int i = 0; i <= 9; i++) {
    num_count[node_id][i] = next_count[i];
    change_table[node_id][i] = next_change_table[i];
  }
}

void update(int update_left, int update_right, int node_id, int node_left,
            int node_right, int x, int y) {

  if (update_right < node_left || update_left > node_right)
    return; // 範囲外なら何もしない
  else if (
      update_left <= node_left &&
      update_right >=
          node_right) { // このノードのカバー区間が、更新区間の部分区間である場合

    for (int i = 0; i <= 9; i++) {
      if ((change_table[node_id][i] == x)) {
        change_table[node_id][i] = y; // 変換対応を更新
      }
    }
    num_count[node_id][y] += num_count[node_id][x];
    num_count[node_id][x] = 0;

    return; // 更新は子方向に伝えない

  } else {
    // このノードのカバー範囲と更新範囲に部分的な重なりがある場合
    // 現在自分が★蓄積していた(子供に伝えていなかった)★変換情報を子に投げる(★★更新区間が、node_left～node_rightであることに注意★★)

    update_array(2 * node_id + 1, change_table[node_id]);
    update_array(2 * node_id + 2, change_table[node_id]);

    for (int i = 0; i <= 9; i++) {
      change_table[node_id][i] = i;
    }

    // 改めて今回のクエリを投げる
    update(update_left, update_right, 2 * node_id + 1, node_left,
           (node_left + node_right) / 2, x, y);
    update(update_left, update_right, 2 * node_id + 2,
           (node_left + node_right) / 2 + 1, node_right, x, y);

    // ★★子にクエリを投げた結果、このノードの以下の集計が変わるので、ボトムアップ的に再帰的に計算する
    for (int i = 0; i <= 9; i++) {
      num_count[node_id][i] =
          num_count[2 * node_id + 1][i] + num_count[2 * node_id + 2][i];
    }
  }
}

int getSum(int search_left, int search_right, int node_id, int node_left,
           int node_right, int x, int y) {
  if (search_right < node_left || search_left > node_right) {
    return 0;
  } else if (search_left <= node_left && search_right >= node_right) {

    int ret = 0;
    for (int i = x; i <= y; i++) {
      ret += num_count[node_id][i];
    }

    return ret;

  } else {

    update_array(2 * node_id + 1, change_table[node_id]);
    update_array(2 * node_id + 2, change_table[node_id]);

    for (int i = 0; i <= 9; i++) {
      change_table[node_id][i] = i;
    }

    int left = getSum(search_left, search_right, 2 * node_id + 1, node_left,
                      (node_left + node_right) / 2, x, y);
    int right = getSum(search_left, search_right, 2 * node_id + 2,
                       (node_left + node_right) / 2 + 1, node_right, x, y);
    return left + right;
  }
}

// オイラーツアーで、ノードのカバー範囲を計算する
void euler_tour(int node_id, int pre_node) {
  LEFT[node_id] = euler_index++;

  for (int i = 0; i < G[node_id].size(); i++) {
    if (G[node_id][i] == pre_node)
      continue;
    euler_tour(G[node_id][i], node_id);
  }
  RIGHT[node_id] = euler_index++;
}

int main() {

  euler_index = 0;
  root = 0;

  int V, Q;
  scanf("%d %d", &V, &Q);

  int from, to;

  for (int loop = 0; loop < V - 1; loop++) {
    scanf("%d %d", &from, &to);
    G[from].push_back(to);
    G[to].push_back(from);
  }

  euler_tour(root, -1);

  int first_N =
      RIGHT[root] +
      1; // セグ木における最下層のノードは、最低RIGHT[root]+1個あれば良い(+1は0オリジンのため)

  init(first_N);

  // 変換配列および集計配列の初期化
  for (int i = 0; i <= 2 * N - 2; i++) {
    for (int k = 0; k <= 9; k++) {
      num_count[i][k] = 0;
      change_table[i][k] = k;
    }
  }

  // 有効ノードの個数を、セグメント木に反映させる
  for (int i = 0; i < V; i++) {
    add(LEFT[i]);
  }

  int command, node_id, x, y;

  int debug = 0;

  for (int loop = 0; loop < Q; loop++) {

    scanf("%d %d %d %d", &command, &node_id, &x, &y);

    /*printf("\\nクエリ%d\\n",loop);
                            printf("LEFT[%d]:%d
       RIHGT:%d\\n",node_id,LEFT[node_id],RIGHT[node_id]);*/

    if (command == 1) { // 計上

      // update(LEFT[node_id],RIGHT[node_id],0,0,N-1,-2,-2);
      // //情報を下に伝播させるためのクエリ
      printf("%d\\n", getSum(LEFT[node_id], RIGHT[node_id], 0, 0, N - 1, x, y));

      debug++;
      if (debug == 193) {

        // printf("%d\\n",getSum(LEFT[node_id],RIGHT[node_id],0,0,N-1,x,y));
        // return 0;
      }

    } else { // 更新

      if (x == y)
        continue;

      update(LEFT[node_id], RIGHT[node_id], 0, 0, N - 1, x, y);
    }
  }

  return 0;
}


Error: 0

Fixed submission:

#include <bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 500001

int N = 1;
int euler_index, root;
int num_count[NUM][10], change_table[NUM][10];
int LEFT[100000], RIGHT[100000];
vector<int> G[100000];

void init(int first_N) {
  while (N < first_N)
    N *= 2;
}

// 最初、全ての電球の明るさは0
void add(int loc) {
  loc += N - 1;

  num_count[loc][0] += 1;

  while (loc > 0) {
    loc = (loc - 1) / 2;
    num_count[loc][0] = num_count[2 * loc + 1][0] + num_count[2 * loc + 2][0];
  }
}

void update(int update_left, int update_right, int node_id, int node_left,
            int node_right, int x, int y) {

  if (update_right < node_left || update_left > node_right)
    return; // 範囲外なら何もしない
  else if (
      update_left <= node_left &&
      update_right >=
          node_right) { // このノードのカバー区間が、更新区間の部分区間である場合

    // printf("部分区間 node_id:%d node_left:%d
    // node_right:%d\\n",node_id,node_left,node_right);
    if (x == y) {
      // printf("変更なし\\n");
      return;
    }

    for (int i = 0; i <= 9; i++) {
      if ((change_table[node_id][i] == x) || (i == x)) {
        change_table[node_id][i] = y; // 変換対応を更新
        // printf("%dが%dになる\\n",i,y);
        if (i == y)
          continue;
        num_count[node_id][y] += num_count[node_id][i];
        num_count[node_id][i] = 0;
      }
    }

    for (int i = 0; i <= 9; i++) {
      if (num_count[node_id][i] > 0) {
        // printf("num_count[%d]:%d\\n",i,num_count[node_id][i]);
      }
    }

    return; // 更新は子方向に伝えない

  } else {
    // このノードのカバー範囲と更新範囲に部分的な重なりがある場合
    // 現在自分が★蓄積していた(子供に伝えていなかった)★変換情報を子に投げる(★★更新区間が、node_left～node_rightであることに注意★★)

    // printf("一部一致 node_id:%d node_left:%d
    // node_right:%d\\n",node_id,node_left,node_right);

    for (int i = 0; i <= 9; i++) {

      if (change_table[node_id][i] == -1)
        continue;
      update(node_left, node_right, 2 * node_id + 1, node_left,
             (node_left + node_right) / 2, i, change_table[node_id][i]);
      update(node_left, node_right, 2 * node_id + 2,
             (node_left + node_right) / 2 + 1, node_right, i,
             change_table[node_id][i]);

      change_table[node_id][i] = -1; // 更新情報は1度投げれば良し
    }

    // 改めて今回のクエリを投げる
    update(update_left, update_right, 2 * node_id + 1, node_left,
           (node_left + node_right) / 2, x, y);
    update(update_left, update_right, 2 * node_id + 2,
           (node_left + node_right) / 2 + 1, node_right, x, y);

    // ★★子にクエリを投げた結果、このノードの以下の集計が変わるので、ボトムアップ的に再帰的に計算する
    for (int i = 0; i <= 9; i++) {
      num_count[node_id][i] =
          num_count[2 * node_id + 1][i] + num_count[2 * node_id + 2][i];
    }
  }
}

int getSum(int search_left, int search_right, int node_id, int node_left,
           int node_right, int x, int y) {
  if (search_right < node_left || search_left > node_right) {
    return 0;
  } else if (search_left <= node_left && search_right >= node_right) {

    int ret = 0;
    for (int i = x; i <= y; i++) {
      ret += num_count[node_id][i];
    }

    return ret;

  } else {

    int left = getSum(search_left, search_right, 2 * node_id + 1, node_left,
                      (node_left + node_right) / 2, x, y);
    int right = getSum(search_left, search_right, 2 * node_id + 2,
                       (node_left + node_right) / 2 + 1, node_right, x, y);
    return left + right;
  }
}

// オイラーツアーで、ノードのカバー範囲を計算する
void euler_tour(int node_id, int pre_node) {
  LEFT[node_id] = euler_index++;

  for (int i = 0; i < G[node_id].size(); i++) {
    if (G[node_id][i] == pre_node)
      continue;
    euler_tour(G[node_id][i], node_id);
  }
  RIGHT[node_id] = euler_index++;
}

int main() {

  euler_index = 0;
  root = 0;

  int V, Q;
  scanf("%d %d", &V, &Q);

  int from, to;

  for (int loop = 0; loop < V - 1; loop++) {
    scanf("%d %d", &from, &to);
    G[from].push_back(to);
    G[to].push_back(from);
  }

  euler_tour(root, -1);

  int first_N =
      RIGHT[root] +
      1; // セグ木における最下層のノードは、最低RIGHT[root]+1個あれば良い(+1は0オリジンのため)

  init(first_N);

  // 変換配列および集計配列の初期化
  for (int i = 0; i <= 2 * N - 2; i++) {
    for (int k = 0; k <= 9; k++) {
      num_count[i][k] = 0;
      change_table[i][k] = -1;
    }
  }

  // 有効ノードの個数を、セグメント木に反映させる
  for (int i = 0; i < V; i++) {
    add(LEFT[i]);
  }

  /*printf("N:%d\\n",N);

  for(int i = 0; i < V; i++){
          printf("LEFT[%d]:%d RIHGT:%d\\n",i,LEFT[i],RIGHT[i]);
  }
  for(int i = 0; i <= 2*N-2; i++){
          printf("num_count[%d][0]:%d\\n",i,num_count[i][0]);
  }*/

  int command, node_id, x, y;

  for (int loop = 0; loop < Q; loop++) {

    scanf("%d %d %d %d", &command, &node_id, &x, &y);

    /*printf("\\nクエリ%d\\n",loop);
                            printf("LEFT[%d]:%d
       RIHGT:%d\\n",node_id,LEFT[node_id],RIGHT[node_id]);*/

    if (command == 1) { // 計上

      update(LEFT[node_id], RIGHT[node_id], 0, 0, N - 1, 0,
             0); // 情報を下に伝播させるためのクエリ
      printf("%d\\n", getSum(LEFT[node_id], RIGHT[node_id], 0, 0, N - 1, x, y));

    } else { // 更新

      if (x == y)
        continue;

      update(LEFT[node_id], RIGHT[node_id], 0, 0, N - 1, x, y);
    }
  }

  return 0;
}