洛谷真题字典树

P8306 【模板】字典树

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int t,n,q;
 4 const int maxn=3000005;
 5 char s[maxn];
 6 int son[maxn][80],cnt[maxn],idx;
 7 int change(char s){
 8 //注意区分大小写字母以及数字 
 9     if(s>='A'&&s<='Z')return s-'A';
10     else if(s>='a'&&s<='z')return s-'a'+26;
11     return s-'0'+52;
12 }
13 void insert(char s[]){
14     int p=0;
15     for(int i=0;s[i];i++){
16         int u=change(s[i]);
17         if(!son[p][u])son[p][u]=++idx;
18         p=son[p][u];
19         cnt[p]++;
20         //此题求前缀,并非一模一样的字符串,cnt[p]++要放在for循环里 
21         //凡是出现过此字符串都计数,不必等到结束 
22     }
23 }
24 int find(char s[]){
25     int p=0;
26     for(int i=0;s[i];i++){
27         int u=change(s[i]);
28         if(!son[p][u])return 0;
29         p=son[p][u];
30     }
31     return cnt[p];
32     //返回出现次数而非是否出现过 
33 }
34 int main(){
35     scanf("%d",&t);
36     while(t--){
37 //        fill(son[0],son[0]+maxn*80,0);
38 //        memset(cnt,0,sizeof cnt);
39         for(int i=0;i<=idx;i++){
40         //不需要将整个数组用fill归零,时间复杂度会爆(3个点
41         //idx记录了改变过几列的值,只需要将操作过的值归零即可 !!! 
42             for(int j=0;j<=80;j++)son[i][j]=0;
43         }
44         for(int i=0;i<=idx;i++)cnt[i]=0;
45         //同son数组,不需要用memset赋值 
46         idx=0;
47         //切记idx归零!!! 
48         scanf("%d%d",&n,&q);
49         for(int i=1;i<=n;i++){
50             cin>>s;
51             insert(s);
52         }
53         while(q--){
54             cin>>s;
55             printf("%d\n",find(s));
56         }
57     }
58     return 0;
59 }

 

posted @ 2022-09-18 09:27  九州霜  阅读(62)  评论(0编辑  收藏  举报