1 #include<iostream>
2 #include<cstring>//对应memset()函数
3 #include<queue>
4 #include<vector>
5 using namespace std;
6 struct Node
7 {
8 Node *fail,*son[26];
9 int cnt;//cnt为0表示初始化,cnt为-1表示已经匹配过
10 int idx;//如果是个模式串匹配完成的单词节点,则idx是该节点对应的模式串在pattern里的下标,否则初始化为0
11 Node()//初始化函数
12 {
13 fail=NULL;
14 memset(son,NULL,sizeof(son));
15 cnt=0;
16 idx=0;
17 }
18 }*root;
19 string str;//存放不定长度的待匹配的文本串
20 queue<Node*>q;
21 vector<string>pattern;//存放不定个数和长度的模式串
22
23 void Init(){//建立trie树
24 string s;
25 root=new Node();
26 Node*p=NULL;
27 while(cin>>s){
28 if(s=="0") break;//模式串输入结束标志
29 pattern.push_back(s);//
30 }
31 for(int i=0;i<pattern.size();i++){
32 p=root;
33 for(int j=0;j<pattern[i].size();j++){//模式串逐个处理
34 int index=pattern[i][j]-'a';
35 if(p->son[index]==NULL)//空,则新建
36 p->son[index]=new Node();
37 p=p->son[index];//往下走
38 }
39 ++p->cnt;//一个模式串匹配结束,该节点cnt为正数
40 p->idx=i;//记录在模式串里下标
41 }
42 }
43
44 void Build_Fail(){//BFS,建立fail函数,
45 //root的子节点的失败指针都指向root。
46 //节点(字符为x)的失败指针指向:从X节点的父节点的fail节点回溯直到找到某节点的子节点也是字符x,没有找到就指向root。
47 root->fail=root;
48 q.push(root);
49 Node *p,*t,*tmp;
50 while(!q.empty()){
51 tmp=p=q.front();
52 q.pop();
53 int b=q.size();
54 for(int i=0;i<26;i++){
55 p=tmp;
56 t=p->son[i];
57 if(t!=NULL){
58 if(p==root)t->fail=root;//第二层的fail全部指向root
59 else{
60 while(p!=root){
61 p=p->fail;
62 if(p->son[i]){
63 t->fail=p->son[i];
64 break;
65 }
66 }
67 if(p->son[i]==NULL)t->fail=root;
68 }
69 q.push(t);//入队
70 }
71 }
72 }
73 }
74
75 void Work(){/*从root节点开始,每次根据读入的字符沿着自动机向下移动。
76 当读入的字符,在分支中不存在时,递归走失败路径。
77 如果走失败路径走到了root节点, 则跳过该字符,处理下一个字符。
78 因为AC自动机是沿着输入文本的最长后缀移动的,所以在读取完所有输入文本后,最后递归走失败路径,直到到达根节点, 这样可以检测出所有的模式。*/
79 cin>>str;
80 Node *p=root,*t;
81 int index,ans=0;
82 for(int i=0;i<str.size();i++){
83 index=str[i]-'a';
84 while(p->son[index]==NULL&&p!=root)p=p->fail;
85 p=p->son[index];
86 if(p==NULL)p=root;
87 t=p;
88 while(t!=root&&t->cnt!=-1){
89 if(t->cnt)
90 cout<<i-pattern[t->idx].size()+1<<'\t'<<t->idx<<'\t'<<pattern[t->idx]<<endl;
91 ans+=t->cnt;
92 t->cnt=-1;
93 t=t->fail;
94 }
95 }
96 }
97
98 int main(){
99 int T;
100 freopen("AC.in","r",stdin);
101 cin>>T;
102 while(T--){
103 Init();
104 Build_Fail();
105 Work();
106 }
107 fclose(stdin);
108 return 0;
109 }
110 /*
111 2
112 she
113 he
114 his
115 her
116 0
117 shers
118 xabc
119 abc
120 b
121 a
122 0
123 xabc
124 */