#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef long long LL; const int MAX = 522133279; const double pi = 3.1415926535897; const int mod = 9973; const int MAXN = 100000; const int branchNum = 26; //字典树的最大分支数,就是26个小写字母 typedef struct TrieNode { int nCount; //至该节点表示的字符串,作为前缀出现的次数 struct TrieNode *next[branchNum]; //子节点列表 }TrieNode; TrieNode memory[2000000 + 100]; int allocp; TrieNode *createTrieNode( ) { TrieNode *node = &memory[allocp++]; // 一旦开始创建一个节点,就说明有对应这个节点的串了,所以count至少为1 node->nCount = 1; for ( int i = 0; i < branchNum; i++ ) node->next[i] = 0; return node; } void trieInsert( TrieNode **pRoot, char *str ) { TrieNode * tmp = *pRoot; int i = 0; while ( str[i] ) { int k = str[i] - 'a'; //找到应该插入的位置 if ( tmp->next[k] ) { // 目前为止的前缀出现了新的对应串 tmp->next[k]->nCount++; } else { tmp->next[k] = createTrieNode( ); } // 继续添加 tmp = tmp->next[k]; i++; } } int trieSearch( TrieNode * root, char * str ) { if ( 0 == root ) return 0; TrieNode *tmp = root; int i = 0; while ( str[i] ) { int k = str[i] - 'a'; // 如果这个位置的字符还有子节点,说明还能找更长的前缀 if ( tmp->next[k] && tmp->next[k]->nCount ) { tmp = tmp->next[k]; } else { return 0; } i++; } // 如果到了这一步,说明至少以str为前缀的字符串在字典中是存在的 return tmp->nCount; } // 删除以str为前缀的所有字符串 int trieDelete( TrieNode * root, char * str ) { // 说明并没有以str为前缀的字符串存在,返回删除失败代码 if ( 0 == trieSearch( root, str ) ) return 0; TrieNode *tmp = root; int i = 0; int len = strlen( str ); while ( str[i] ) { int k = str[i] - 'a'; tmp->nCount--; if ( i == len - 1 ) { tmp->next[k] = 0; return 1; } tmp = tmp->next[k]; i++; } return 0; } int main( ) { int N; char op[10], str[40]; scanf( "%d", &N ); TrieNode *root = createTrieNode( ); while ( N-- ) { scanf( "%s%s", op, str ); if ( op[0] == 'i' ) { trieInsert( &root, str ); } else if ( op[0] == 'd' ) { trieDelete( root, str ); } else { if ( 0 == trieSearch( root, str ) ) { puts( "No" ); } else { puts( "Yes" ); } } } return 0; } /* 5 i hello d he s hel */