CH601后缀数组【Trie树】

内含字典树创建及查询模板

1601 前缀统计 0x10「基本数据结构」例题

描述

给定N个字符串S1,S2...SN,接下来进行M次询问,每次询问给定一个字符串T,求S1~SN中有多少个字符串是T的前缀。输入字符串的总长度不超过10^6,仅包含小写字母。

输入格式

第一行两个整数N,M。接下来N行每行一个字符串Si。接下来M行每行一个字符串表示询问。

输出格式

对于每个询问,输出一个整数表示答案

样例输入

3 2
ab
bc
abc
abc
efg

样例输出

2
0

思路:

用scanf !=EOF最后一组不知道为什么就是会RE

虐狗宝典字典树笔记:

Trie树,字典树每个节点拥有若干个字符指针,在插入或检索字符串时扫到一个字符c就沿着当前节点的c字符指针走下去。

初始时,空Trie仅包含一个根节点,字符指针均为空。

插入S时,我们令一个指针p指向根节点,依次扫描S中的每一个字符c。

  1.若p的c字符指针指向一个已经存在的节点Q,则令P=Q

  2.若p的c字符指针指向空,则新建一个节点Q,令p的c字符指针指向Q,然后令P=Q

  当S扫描完毕,当前节点P上标记他是一个字符串的末尾

检索S是否在Trie中存在,令一个指针P指向根节点,依次扫描S中的每个字符c

  1.若P的c字符指针指向空,则说明S没有被插入过Trie,结束检索

  2.若P的c字符指针指向一个已经存在的节点Q,则令P=Q

  当S中的字符扫描完毕,若当前节点P被标记为一个字符串的末尾,说明S在Trie中存在。

本题与讲解的不同之处在于末尾应标记出现的次数,检索时也应该同时统计所经过节点的作为末尾的次数。

 1 #include <iostream>
 2 #include <set>
 3 #include <cmath>
 4 #include <stdio.h>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <map>
 8 using namespace std;
 9 typedef long long LL;
10 #define inf 0x7f7f7f7f
11 
12 int n, m;
13 const int maxn = 1e6 + 10;
14 int trie[maxn][26], tot = 1, ed[maxn];
15 char s[maxn];
16 
17 void insertt(char *str)
18 {
19     int len = strlen(str), p = 1;
20     for(int k = 0; k < len; k++){
21         int ch = str[k] - 'a';
22         if(trie[p][ch] == 0){
23             trie[p][ch] = ++tot;
24         }
25         p = trie[p][ch];
26     }
27     ed[p]++;
28 }
29 
30 int searchh(char* str)
31 {
32     int ans = 0;
33     int len = strlen(str), p = 1;
34     for(int k = 0; k < len; k++){
35         
36         p = trie[p][str[k] - 'a'];
37         if(p == 0)return ans;
38         ans += ed[p];
39     }
40     //ans += ed[p];
41     return ans;
42 }
43 
44 int main()
45 {
46     scanf("%d%d", &n, &m);
47 
48     for(int i = 1; i <= n; i++){
49         scanf("%s", s);
50         insertt(s);
51     }
52     for(int j = 1; j <= m; j++){
53         scanf("%s", s);
54         printf("%d
", searchh(s));
55     }
56     return 0;
57 }
原文地址:https://www.cnblogs.com/wyboooo/p/9824073.html