传..传送:http://acm.hdu.edu.cn/showproblem.php?pid=5687
Problem C
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2697 Accepted Submission(s): 743
Problem Description
度熊手上有一本神奇的字典,你可以在它里面做如下三个操作:
1、insert : 往神奇字典中插入一个单词
2、delete: 在神奇字典中删除所有前缀等于给定字符串的单词
3、search: 查询是否在神奇字典中有一个字符串的前缀等于给定的字符串
1、insert : 往神奇字典中插入一个单词
2、delete: 在神奇字典中删除所有前缀等于给定字符串的单词
3、search: 查询是否在神奇字典中有一个字符串的前缀等于给定的字符串
Input
这里仅有一组测试数据。第一行输入一个正整数N(1≤N≤100000),代表度熊对于字典的操作次数,接下来N行,每行包含两个字符串,中间中用空格隔开。第一个字符串代表了相关的操作(包括: insert, delete 或者 search)。第二个字符串代表了相关操作后指定的那个字符串,第二个字符串的长度不会超过30。第二个字符串仅由小写字母组成。
Output
对于每一个search 操作,如果在度熊的字典中存在给定的字符串为前缀的单词,则输出Yes 否则输出 No。
Sample Input
5
insert hello
insert hehe
search h
delete he
search hello
Sample Output
Yes
No
Source
解题思路:
输入查询都是字典树基本操作,这里的字典树的删除是一种标记删除而不是物理删除(非最后节点)。
但是这里的标记删除要注意的是不能直接取消标记或标记为 0 ,而是要根据要删除的字符串在字典中出现的次数,然后根据这个次数去更新路径上的点的标记。如果是删除字符的最后节点则进行物理删除。
例如说:字典里是 zzaizjja,zzaizjj,要删除 zzaizjja,如果单纯把路径 zzaizjja 上的节点都更新为0,则它的子串也 out 了,所以正确的更新是:路径上的点减去zzaizjja出现的次数。
AC Code:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 #define INF 0x3f3f3f3f 7 #define LL long long int 8 #define Bits 26 9 using namespace std; 10 const int MAXN = 33; 11 int N; 12 struct Trie 13 { 14 Trie *next[Bits]; 15 int flag; 16 inline void init(){ 17 this->flag = 1; 18 for(int i = 0; i < Bits; i++) 19 this->next[i] = NULL; 20 } 21 }; 22 Trie *Root = (Trie *)malloc(sizeof(Trie)); 23 inline void DelTrie(Trie *t) 24 { 25 if(t == NULL) return; 26 for(int i = 0; i < Bits; i++){ 27 if(t->next[i]!=NULL) DelTrie(t->next[i]); 28 }free(t); 29 return; 30 } 31 32 void Create_Trie(char *str, bool isDel) 33 { 34 int len = strlen(str); 35 Trie *p = Root, *temp; 36 int Delnum = 0; 37 for(int i = 0; i < len; i++){ 38 int index = str[i]-'a'; 39 if(!isDel){ 40 if(p->next[index] == NULL){ 41 temp = (Trie *)malloc(sizeof(Trie)); 42 temp->init(); 43 p->next[index] = temp; 44 p = p->next[index]; 45 } 46 else{p->next[index]->flag+=1; p=p->next[index];} 47 } 48 else{ 49 if(p->next[index] != NULL){ 50 Delnum = p->next[index]->flag; 51 p = p->next[index]; 52 }else return; 53 } 54 } 55 if(isDel){ 56 p = Root; 57 for(int i = 0; i < len; i++){ 58 int index = str[i]-'a'; 59 if(p->next[index] == NULL) return; 60 if(i==len-1){ 61 DelTrie(p->next[index]); 62 p->next[index] = NULL; 63 return; 64 } 65 p->next[index]->flag-=Delnum; 66 p = p->next[index]; 67 } 68 } 69 } 70 71 72 bool Find_Trie(char *str) 73 { 74 int len = strlen(str); 75 Trie *p = Root; 76 for(int i = 0; i < len; i++){ 77 int index = str[i]-'a'; 78 if(p->next[index] != NULL && p->next[index]->flag > 0) 79 p=p->next[index]; 80 else return false; 81 }return true; 82 } 83 84 int main() 85 { 86 Root->init(); 87 scanf("%d", &N); 88 char str[MAXN], command[10]; 89 while(N--){ 90 scanf("%s", command); 91 if(strcmp(command, "insert")==0){ 92 scanf("%s", str); 93 Create_Trie(str, false); 94 } 95 else if(strcmp(command, "delete")==0){ 96 //puts("zjj"); 97 scanf("%s", str); 98 Create_Trie(str, true); 99 } 100 else{ 101 scanf("%s", str); 102 if(Find_Trie(str)) puts("Yes"); 103 else puts("No"); 104 } 105 }DelTrie(Root); 106 return 0; 107 }