题目描述
给你一个文本串 S 和 n 个模式串 T 1.. n T_{1..n} T1..n,请你分别求出每个模式串 T i T_i Ti 在 S 中出现的次数。
输入格式
第一行包含一个正整数 n 表示模式串的个数。
接下来 n 行,第 i 行包含一个由小写英文字母构成的字符串 T i T_i Ti。
最后一行包含一个由小写英文字母构成的字符串 S。
输出格式
输出包含 n 行,其中第 iii 行包含一个非负整数表示 T i T_i Ti 在 S 中出现的次数。
输入输出样例
输入 #1
5
a
bb
aa
abaa
abaaa
abaaabaa
输出 #1
6
0
3
2
1
说明/提示
1 ≤ n ≤ 2 × 1 0 5 1≤n≤2×10^5 1≤n≤2×105, T 1.. n T_{1..n} T1..n 的长度总和不超过 2 × 1 0 5 2×10^5 2×105,S 的长度不超过 2 × 1 0 6 2×10^6 2×106。
#include<bits/stdc++.h>
#define maxn 2000001
using namespace std;
char s[maxn],T[maxn];
int n,cnt,vis[200051],ans,in[maxn],Map[maxn];
struct kkk{
int son[26],fail,flag,ans;
void clear(){memset(son,0,sizeof(son)),fail=flag=ans=0;}
}trie[maxn];
queue<int>q;
void insert(char* s,int num){
int u=1,len=strlen(s);
for(int i=0;i<len;i++){
int v=s[i]-'a';
if(!trie[u].son[v])trie[u].son[v]=++cnt;
u=trie[u].son[v];
}
if(!trie[u].flag)trie[u].flag=num;
Map[num]=trie[u].flag;
}
void getFail(){
for(int i=0;i<26;i++)trie[0].son[i]=1;
q.push(1);
while(!q.empty()){
int u=q.front();q.pop();
int Fail=trie[u].fail;
for(int i=0;i<26;i++){
int v=trie[u].son[i];
if(!v){trie[u].son[i]=trie[Fail].son[i];continue;}
trie[v].fail=trie[Fail].son[i]; in[trie[v].fail]++;
q.push(v);
}
}
}
void topu(){
for(int i=1;i<=cnt;i++)
if(in[i]==0)q.push(i);
while(!q.empty()){
int u=q.front();q.pop();vis[trie[u].flag]=trie[u].ans;
int v=trie[u].fail;in[v]--;
trie[v].ans+=trie[u].ans;
if(in[v]==0)q.push(v);
}
}
void query(char* s){
int u=1,len=strlen(s);
for(int i=0;i<len;i++)
u=trie[u].son[s[i]-'a'],trie[u].ans++;
}
int main(){
scanf("%d",&n); cnt=1;
for(int i=1;i<=n;i++){
scanf("%s",s);
insert(s,i);
}getFail();scanf("%s",T);
query(T);topu();
for(int i=1;i<=n;i++)printf("%d\n",vis[Map[i]]);
}