注意每个串只能成为一个串的子串 only once
所以用set去重
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <math.h>
#include <queue>
using namespace std;
#define ll __int64
#define N 10010
#define inf 100000000000000
#define maxnode 250001
#define sigma_size 26
struct Trie{
int ch[maxnode][sigma_size];
int val[maxnode]; //该单词在模式串中出现的次数
int last[maxnode];
int f[maxnode]; //失配数组
int num[maxnode]; //该单词出现在文本串的次数
int pre[maxnode]; //该单词的前驱
int len[maxnode]; //以该单词结尾的单词长度
int Char[maxnode]; //该单词对应的字母
int sz;
void init(){
sz=1;
memset(ch,0,sizeof(ch));
memset(val, 0, sizeof(val));
memset(f,0,sizeof(f));
memset(last,0,sizeof(last)); //记录该节点前一个节点是谁
memset(len, 0, sizeof(len));
}
int idx(char c){ return c-'a'; }
int insert(char *s){
int u = 0;
for(int i = 0; s[i] ;i++){
int c = idx(s[i]);
if(!ch[u][c])
ch[u][c] = sz++;
pre[ch[u][c]] = u;
Char[ch[u][c]] = s[i];
len[ch[u][c]] = len[u]+1;
u = ch[u][c];
}
val[u] = 1;
num[u] = 0;
return u;
}
void getFail(){
queue<int> q;
for(int i = 0; i<sigma_size; i++)
if(ch[0][i]) q.push(ch[0][i]);
while(!q.empty()){
int r = q.front(); q.pop();
for(int c = 0; c<sigma_size; c++){
int u = ch[r][c];
if(!u)continue;
q.push(u);
int v = f[r];
while(v && ch[v][c] == 0) v = f[v]; //沿失配边走上去 如果失配后有节点 且 其子节点c存在则结束循环
f[u] = ch[v][c];
}
}
}
void find(char *T){
set<int>myset; myset.clear();
int j = 0;
for(int i = 0; T[i] ; i++){
int c = idx(T[i]);
while(j && ch[j][c]==0) j = f[j];
j = ch[j][c];
int temp = j;
while(temp){ //沿失配边走 || 若沿失配边走时一定要节点为单词结尾则改成while(temp && val[temp])
if(myset.find(temp)==myset.end()){
myset.insert(temp);
num[temp]++;
}
temp = f[temp];
}
}
}
}ac;
int Stack[100010];
char s[30], hehe[N][30];
int main(){
int n, que, i;
ac.init();
scanf("%d",&n);
for(i = 0; i < n; i++)scanf("%s",hehe[i]);
scanf("%d",&que);
for(i = 0; i < que; i++){
scanf("%s",s);
Stack[i] = ac.insert(s);
}
ac.getFail();
for(i = 0; i < n; i++)ac.find(hehe[i]);
for(i = 0; i < que; i++)printf("%d\n",ac.num[Stack[i]]);
return 0;
}