// competitive-verifier: PROBLEM https://yukicoder.me/problems/no/2020 #include #include #include #include #include /// @brief Trie /// @see https://algo-logic.info/trie-tree/ /// @see https://atcoder.jp/contests/tenka1-2016-final-open/tasks/tenka1_2016_final_c template struct Trie { private: struct _node { std::vector next_node; int count; ///< このノードを通過した文字列の本数(= このノードに対応する接頭辞を持つ文字列数) _node() : next_node(char_size, -1), count(0) {} }; public: using node_type = _node; Trie() : root(0), nodes() { nodes.emplace_back(); } int size() const { return nodes.size(); } /// @brief ノード node_id の子 c をたどる。無ければ新規作成。count は更新しない。 /// @return 子ノードの id int add(int node_id, char ch) { assert(0 <= node_id && node_id < (int)nodes.size()); int c = ch - base; assert(0 <= c && c < char_size); int &next_id = nodes[node_id].next_node[c]; if (next_id == -1) { next_id = nodes.size(); nodes.emplace_back(); } return next_id; } /// @brief ノード node_id の通過カウントを増やす。 void add_count(int node_id, int x = 1) { assert(0 <= node_id && node_id < (int)nodes.size()); nodes[node_id].count += x; } /// @brief ノード node_id の通過カウント(接頭辞を持つ文字列数)。 int count(int node_id) const { assert(0 <= node_id && node_id < (int)nodes.size()); return nodes[node_id].count; } std::vector insert(const std::string &word) { std::vector res; int node_id = 0; for (int i = 0; i < (int)word.size(); ++i) { int c = word[i] - base; int &next_id = nodes[node_id].next_node[c]; if (next_id == -1) { next_id = nodes.size(); nodes.emplace_back(); } node_id = next_id; ++nodes[node_id].count; res.emplace_back(node_id); } return res; } int search_id(const std::string &word) { int node_id = 0; for (int i = 0; i < (int)word.size(); ++i) { int c = word[i] - base; int &next_id = nodes[node_id].next_node[c]; if (next_id == -1) return -1; node_id = next_id; } return node_id; } node_type get_node(int node_id) const { assert(0 <= node_id && node_id < (int)nodes.size()); return nodes[node_id]; } private: int root; std::vector nodes; }; // S_x と全 S_k の最長共通接頭辞長の総和は、S_x が通る Trie のパス上の // 各ノードの「通過文字列数(count)」の総和に等しい。 int main() { int n; std::cin >> n; Trie<26, 'a'> trie; std::vector> path(n); ///< path[i]: S_i がたどるノード id 列 for (int i = 0; i < n; ++i) { std::string s; std::cin >> s; path[i] = trie.insert(s); } int q; std::cin >> q; while (q--) { int type; std::cin >> type; if (type == 1) { int x; char c; std::cin >> x >> c; --x; int parent = path[x].empty() ? 0 : path[x].back(); int nid = trie.add(parent, c); trie.add_count(nid); path[x].emplace_back(nid); } else { int x; std::cin >> x; --x; std::uint64_t ans = 0; for (int nid : path[x]) ans += trie.count(nid); std::cout << ans << '\n'; } } return 0; }