Problem C
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1196 Accepted Submission(s): 371
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
题目链接:HDU 5687
本来以为是一道字典树水题,结果被坑了十几发WA,哭晕在厕所。
比较接近正解的写法是用一个cnt记录字典树路径上被覆盖的次数然后寻找的时候仅判断这个节点的cnt是否为0即可,然而这样做有一个比较恶心的bug想了很久才发现,考虑这样一个例子
100
i abcd
d abc
i abc
s abcd
显然上述过程中a-b-c-d的c-d会断开,然后又被接上,会输出Yes,实际上此时abc是存在的,abcd早就被delete掉了,原因就是在cnt变为0的时候没有把以前的“关系”解除掉,因此在删除的时候若一个节点的cnt变为0,则把这个节点的父亲节点的指针置空即可,即要让这个儿子消失
代码:
#include <stdio.h> #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 100010; struct Trie { int nxt[26]; int cnt; void reset() { fill(nxt, nxt + 26, 0); cnt = 0; } }; Trie L[N * 35]; int sz; void init() { sz = 1; L[0].reset(); } void update(char s[]) { int cur = 0; int len = strlen(s); for (int i = 0; i < len; ++i) { int v = s[i] - 'a'; if (!L[cur].nxt[v]) { L[sz].reset(); L[cur].nxt[v] = sz++; } cur = L[cur].nxt[v]; ++L[cur].cnt; } } bool Find(char s[]) { int cur = 0; int len = strlen(s); for (int i = 0; i < len; ++i) { int v = s[i] - 'a'; if (!L[cur].nxt[v]) return false; cur = L[cur].nxt[v]; } return true; } void del(char s[]) { int cur = 0; int len = strlen(s); int Min = INF; for (int i = 0; i < len; ++i) { int v = s[i] - 'a'; if (!L[cur].nxt[v]) return ; cur = L[cur].nxt[v]; if (L[cur].cnt < Min) Min = L[cur].cnt; } if (Min) { int fa = 0; for (int i = 0; i < len; ++i) { int v = s[i] - 'a'; int cur = L[fa].nxt[v]; L[cur].cnt -= Min; if (!L[cur].cnt)//断开最开始的儿子即可,后面就不会再被用到 { L[fa].nxt[v] = 0; return ; } fa = cur; } } } int main(void) { int n; char ops[10], s[35]; while (~scanf("%d", &n)) { init(); while (n--) { scanf("%s%s", ops, s); if (ops[0] == 'i') update(s); else if (ops[0] == 's') puts(Find(s) ? "Yes" : "No"); else del(s); } } return 0; }