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

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

// 前2文字を選んで消す <=> 一番前から何文字か消して、1文字復活させる
// s から t を得る <=> s と t は末尾 len(t) - 1 文字一致、s の冒頭 len(s) -
// len(t) + 1 文字のどれかが t の冒頭 1 文字と一致

using count_t = int32_t;

struct Node {
  char c;
  unordered_set<char> leaf;
  map<char, Node> child;
  // vector<count_t> num_substr;
  count_t num_child;
};

void construct(Node &node, const string &s, const size_t i) {
  if (i == s.size() - 1) {
    node.leaf.emplace(s[i]);
  } else {
    if (node.child.count(s[i]) == 0) {
      node.child[s[i]] = Node{s[i], {}, {}, 0};
    }
    construct(node.child[s[i]], s, i + 1);
  }
}

void print(const Node &node) {
  cout << "{" << node.c << "[";
  // for(const auto &n: node.num_substr)cout << n << ",";
  cout << "]\\n";
  for (const auto &c : node.leaf)
    cout << c << "+";
  for (const auto &c : node.child) {
    print(c.second);
    cout << "+";
  }
  cout << "}";
}

// 葉ノードが文字cを含むなら、子ノードで文字cを含む部分文字列の数だけペアができる
// 「子ノードで文字cを含む部分文字列」を上に向かって数え上げていく
// void traverse(Node &node){
//     // 長さ3以上の部分列の個数は、子たちの部分列の個数の総和
//     node.num_child = node.leaf.size();
//     for(auto &child_node: node.child){
//         traverse(child_node.second);
//         for(auto i=0; i<26; ++i){
//             node.num_substr[i] += child_node.second.num_substr[i];
//         }
//         node.num_child += child_node.second.num_child;
//     }
//     node.num_substr[node.c - 'a'] = node.num_child;
//     for (const auto &c: node.leaf){
//         if (c != node.c) node.num_substr[c - 'a']++;
//     }
// }

pair<ll, vector<count_t>> traverse_count(Node &node) {
  node.num_child = node.leaf.size();
  auto node_count = vector<count_t>(26);
  ll ret = 0;
  for (auto &child_node : node.child) {
    const auto child_node_count = traverse_count(child_node.second);
    for (auto i = 0; i < 26; ++i) {
      node_count[i] += child_node_count.second[i];
    }
    node.num_child += child_node.second.num_child;
    ret += child_node_count.first;
    for (const auto &c : node.leaf) {
      ret += child_node_count.second[c - 'a'];
    }
  }
  node_count[node.c - 'a'] = node.num_child;
  for (const auto &c : node.leaf) {
    if (c != node.c)
      node_count[c - 'a']++;
  }
  return {ret, node_count};
}

// ll count(const Node &node){
//     ll ret=0;
//     for(const auto &child_node: node.child){
//         ret += count(child_node.second);
//     }
//     for(const auto &c: node.leaf){
//         for(const auto &child_node: node.child){
//             ret+=child_node.second.num_substr[c-'a'];
//         }
//     }
//     return ret;
// }

int main() {
  int n;
  cin >> n;
  auto trie = Node{'a', {}, {}, 0};
  for (int i = 0; i < n; ++i) {
    string s;
    cin >> s;
    reverse(s.begin(), s.end());
    construct(trie, s, 0);
  }
  // traverse(trie);
  //  print(trie);
  //  cout << "\\n\\n";
  cout << traverse_count(trie).first;
  return 0;
}


Error: WA

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

// 前2文字を選んで消す <=> 一番前から何文字か消して、1文字復活させる
// s から t を得る <=> s と t は末尾 len(t) - 1 文字一致、s の冒頭 len(s) -
// len(t) + 1 文字のどれかが t の冒頭 1 文字と一致

using count_t = int32_t;

struct Node {
  char c;
  unordered_set<char> leaf;
  map<char, Node> child;
  vector<count_t> num_substr;
  count_t num_child;
};

void construct(Node &node, const string &s, const size_t i) {
  if (i == s.size() - 1) {
    node.leaf.emplace(s[i]);
  } else {
    if (node.child.count(s[i]) == 0) {
      node.child[s[i]] = Node{s[i], {}, {}, vector<count_t>(26), 0};
    }
    construct(node.child[s[i]], s, i + 1);
  }
}

void print(const Node &node) {
  cout << "{" << node.c << "[";
  for (const auto &n : node.num_substr)
    cout << n << ",";
  cout << "]\\n";
  for (const auto &c : node.leaf)
    cout << c << "+";
  for (const auto &c : node.child) {
    print(c.second);
    cout << "+";
  }
  cout << "}";
}

// 葉ノードが文字cを含むなら、子ノードで文字cを含む部分文字列の数だけペアができる
// 「子ノードで文字cを含む部分文字列」を上に向かって数え上げていく
void traverse(Node &node) {
  // 長さ3以上の部分列の個数は、子たちの部分列の個数の総和
  node.num_child = node.leaf.size();
  for (auto &child_node : node.child) {
    traverse(child_node.second);
    for (auto i = 0; i < 26; ++i) {
      node.num_substr[i] += child_node.second.num_substr[i];
    }
    node.num_child += child_node.second.num_child;
  }
  node.num_substr[node.c - 'a'] = node.num_child;
  for (const auto &c : node.leaf) {
    if (c != node.c)
      node.num_substr[c - 'a']++;
  }
}

ll count(const Node &node) {
  ll ret = 0;
  for (const auto &child_node : node.child) {
    ret += count(child_node.second);
  }
  for (const auto &c : node.leaf) {
    for (const auto &child_node : node.child) {
      ret += child_node.second.num_substr[c - 'a'];
    }
  }
  return ret;
}

int main() {
  int n;
  cin >> n;
  auto trie = Node{'a', {}, {}, vector<count_t>(26), 0};
  for (int i = 0; i < n; ++i) {
    string s;
    cin >> s;
    for (const auto &si : s) {
      if (!(si >= 'a' && si <= 'z')) {
        cout << 0;
        return 0;
      }
    }
    reverse(s.begin(), s.end());
    construct(trie, s, 0);
  }
  traverse(trie);
  // print(trie);
  // cout << "\\n\\n";
  cout << count(trie);
  return 0;
}