【模板】 ac自动机
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #define maxn 5000000+10 6 using namespace std; 7 char str[maxn*2]; 8 struct node{ 9 int fail;//失配指针; 10 int cnt;//单词出现的次数; 11 int next[62];// 此节点的下一个(儿子)节点; 12 }trie[maxn];//节点结构体; 13 int k=0,ans=0; 14 queue<int> q;//队列:建失配指针使用; 15 void build_trie(int id,char *s)//id表示第几个结点,即所有字符串从第0个节点开始向下建;*s即表示这个字符串; 16 { 17 int len=strlen(s);//该字符串的长度;(相当于字符串最后一个字符的深度) 18 int j=0; 19 for(int i=0;i<len;i++){ 20 j=s[i]-'a'; 21 if(trie[id].next[j]==0)/*若此字母未出现在当前位置的下一深度*/ 22 { 23 trie[id].next[j]=++k;//当前节点对于j字母节点的位置;即j字母的节点序号; 24 } 25 id=trie[id].next[j];//id传为下一字母的地址; 26 } 27 trie[id].cnt++;//对此单词的数量++; 28 } 29 void build_fail(int id) 30 { 31 while(!q.empty()) q.pop();//为了放心,(be afraid of队列未清空) 32 for(int i=0;i<26;i++)//遍历超级节点下的26个字母; 33 { 34 int j=trie[id].next[i]; 35 if(j!=0){ 36 q.push(j); 37 trie[j].fail=id;//第一层的节点失配指针皆指向超级节点; 38 } 39 } 40 while(!q.empty()) 41 { 42 int now=q.front();q.pop();//取出当前位置;(队首元素) 43 for(int i=0;i<26;i++) 44 { 45 int j=trie[now].next[i]; 46 if(j==0)//当前位置下没有这个节点;就调到它失配指针所指向的节点下的此个字母节点; 47 { 48 trie[now].next[i]=trie[trie[now].fail].next[i];//若为0,不影响,指向超级节点; 49 continue;//该点遍历完成,直接进入下一节点的遍历; 50 } 51 trie[j].fail=trie[trie[now].fail].next[i];//如果当前位置下有这个字母节点,则其失配指针指向当前位置的失配指针下的该节点; 52 //若当前位置的失配指针下没有当前遍历的该字母节点,任不影响(为0,指向超级节点); 53 q.push(j);//存入数组; 54 } 55 } 56 } 57 void solve_trie(int id,char *s)//查询函数; 58 { 59 int len=strlen(s),j=0; 60 for(int i=0;i<len;i++) 61 { 62 int j=trie[id].next[s[i]-'a'];//当前位置的下一个节点位置; 63 while(j && trie[j].cnt!=-1)//当此节点存在同时其cnt未被遍历; 64 { 65 ans+=trie[j].cnt;//将答案加上所搜索的字符串中所包含的该单词数 ; 66 trie[j].cnt=-1;//标记(因为是看有多少个模式串出现过,而不是出现多少次) 67 j=trie[j].fail;//直接将位置指向其失配指针的位置(节约时间)(也就是找匹配了的模式串的fail)(就是删除模式串前面的一部分的模式串) 68 //一个fail就是把匹配的串的前面一部分删去,而建立的字典树是模式串 69 } 70 id=trie[id].next[s[i]-'a'];//id继承,当前位置的下一个节点; 0也没关系 71 } 72 } 73 int main() 74 { 75 int n; 76 scanf("%d",&n); 77 for(int i=1;i<=n;i++) 78 { 79 scanf("%s",str);//第i个短字符串; 80 build_trie(0,str);//0为超级根节点(即所有字符串的共同祖先);(即从0开始建) 81 }//字典树建立完成; 82 build_fail(0);//建失配指针; 83 scanf("%s",str);//输入需查询的字符串; 84 solve_trie(0,str); //查询; 85 printf("%d\n",ans);//输出; 86 return 0; 87 } 88 //https://www.luogu.org/problemnew/solution/P3808 89 //还有最好用gets