嗯...
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2846
这与裸的字典树略有差别:
因为题目要求有n个字符串,m个询问 问字符串在n个字符串中出现过多少次,
即为一个字串的问题,所以我们把一个字符串拆开分别建树。
eg:
abcd 中有a,b,c,d,abcd,bcd,cd,bc,abc...
我们可以将abcd拆成abcd bcd cd d 分别建树
注意:
abab会导致重复,所以用flag标记:若此编号不同于所给编号(此后缀在本要查的字符串中没有)才加1,这样就避免了重复。
AC代码:

1 #include<cstdio>
2 #include<iostream>
3 #include<cstring>
4
5 using namespace std;
6
7 int ch[500005][30];
8 int flag[500005];
9 int val[500005];
10 int cnt = 1;
11
12 inline int ids(char c){
13 return c - 'a';
14 }
15
16 inline void build(char *s, int k){
17 int u = 0;
18 int len = strlen(s);
19 for(int i = 0; i < len; i++){
20 int id = ids(s[i]);
21 if(!ch[u][id]) ch[u][id] = cnt++;
22 u = ch[u][id];
23 if(flag[u] != k){
24 val[u]++;
25 flag[u] = k;
26 }
27 }
28 }
29
30 inline int query(char *s){
31 int len = strlen(s);
32 int u = 0;
33 for(int i = 0; i < len; i++){
34 int id = ids(s[i]);
35 if(!ch[u][id]) return 0;
36 u = ch[u][id];
37 }
38 return val[u];
39 }
40
41 int main(){
42 int p, q;
43 char s[25];
44 scanf("%d", &p);
45 memset(flag, -1, sizeof(flag));
46 for(int i = 1; i <= p; i++){
47 scanf("%s", s);
48 int len = strlen(s);
49 for(int j = 0; j < len; j++)
50 build(s + j, i);
51 }
52 scanf("%d", &q);
53 for(int i = 0; i < q; i++){
54 scanf("%s", s);
55 printf("%d\n", query(s));
56 }
57 return 0;
58 }
