#include <iostream> using namespace std;const int N = 1e6 + 10;// Trie树是一个集合,可以存储字符串 // son二维数组中,每行代表一个节点,该行的每列都是它的儿子,最多26列代表一个节点最多26个儿子(题目中说了都是小写字母) // cnt[i]代表以序号为i的节点结尾的字符串有多少个 // idx代表当前可用序号 int son[N][26], cnt[N], idx;// 构造Trie树 void insert(string s) {// p代表当前节点的序号; 根节点序号为0,初始时p是根节点int p = 0; for (int i = 0; i < s.size(); i ++ ){// 将字符串中的26种小写字母映射到0~25int u = s[i] - 'a';// 如果p节点中的所有子节点没有该字符,给该字符一个序号,相当于创建了新节点if (!son[p][u]) son[p][u] = ++ idx;// 让p指向这个新节点p = son[p][u];}// 字符串在树中插入结束后,最后一个元素作为叶子节点,标记以该节点结尾的字符串的个数多一个cnt[p] ++ ; }// 查询集合中某个字符串的个数 int query(string s) {// 根节点序号为0,从根节点开始查int p = 0;for (int i = 0; i < s.size(); i ++ ){// 当前字符映射到0~25int u = s[i] - 'a';// 如果p节点中的所有子节点没有该字符,说明该字符串在树中不存在,个数为0if (!son[p][u]) return 0;// 如果当前字符存在,p指向当前字符的节点p = son[p][u];}// cnt[p]代表以p序号节点结尾的字符串的个数return cnt[p]; }int main() {int n;cin >> n;while (n -- ){char op;string x;cin >> op >> x;if (op == 'I'){insert(x);}else if (op == 'Q'){cout << query(x) << endl;}}return 0; }