#include <array> #include <iostream> using namespace std; // 根据左神静态数组的思路写的, 不需要动态内存管理了 // https://www.bilibili.com/video/BV1Yu4y1Q7vR/?spm_id_from=333.999.0.0&vd_source=8ea6dc6c02215b66383cf6ab9791e3b4 class TrieTree { public: static constexpr int MAXN = 150001; // 操作数是10^5, 还有字符串长度, 理论上要添加的新节点最多1.5*10^5 + 1 ?? 感觉不像? std::array<std::array<int, 26>, MAXN> tree; std::array<int, MAXN> pass; std::array<int, MAXN> end; int cnt = 1; // 默认下标0不用 TrieTree() { clear(); } void clear(/*void*/) { cnt = 1; // 二维数组, 没想到合适一次性清空API TODO for (auto &item : tree) { item.fill(0); } pass.fill(0); end.fill(0); } void insert(const std::string &s) { int cur = 1; pass[cur]++; int path; for (char ch : s) { path = ch - 'a'; if (tree[cur][path] == 0) { tree[cur][path] = ++cnt; } cur = tree[cur][path]; pass[cur]++; } end[cur]++; // 字符串为空好像也能添加 } // 找到最后一个字符的的节点 // 找不到返回0 int getTreeEnd(const std::string &s) { int cur = 1; int path; for (char ch : s) { path = ch - 'a'; if (tree[cur][path] == 0) { return 0; } cur = tree[cur][path]; } return cur; } int search(const std::string &s) { int cur = getTreeEnd(s); // 逻辑类似, 合并同类项了 if (cur == 0) {return 0;} return end[cur]; } int prefixNumber(const std::string &s) { int cur = getTreeEnd(s); if (cur == 0) {return 0;} return pass[cur]; } // delete是关键词,就避免使用了 void remove(const std::string &s) { if (search(s) == 0) {return;} // 前缀树有对应的字符串才删除 int cur = 1; pass[cur]--; // note : 首元素应该也要减的, 不然前缀树上已经存了多少个字符串的信息的错误的 // 空字符串也是能添加的, 首元素为0, 不能删除首元素, 特殊处理 int path; for (char ch : s) { // 下一个节点pass减到0了, 后面不在处理 // 直接遗弃, 对应的节点内存也不使用了 path = ch - 'a'; if (--pass[tree[cur][path]] == 0) { tree[cur][path] = 0; return; // note : } cur = tree[cur][path]; } end[cur]--; } }; int main() { int n; int op; std::string str; TrieTree trie; while (std::cin >> n) { trie.clear(); while (n--) { std::cin >> op >> str; switch (op) { case 1: // 添加 trie.insert(str); break; case 2: // 删除 trie.remove(str); break; case 3: // 查询str的单词数量 std::cout << (trie.search(str) > 0 ? "YES" : "NO" ) << std::endl; break; case 4: // 返回str前缀的单词数量 std::cout << trie.prefixNumber(str) << std::endl; break; } } } } // 64 位输出请用 printf("%lld")