<span style="font-family: Arial, Helvetica, sans-serif;">//没有重复单词</span>
<span style="font-family: Arial, Helvetica, sans-serif;"># include <stdio.h></span>
# include <algorithm>
# include <queue>
# include <string.h>
using namespace std;
# define kind 128
struct node
{
node *fail;//失败指针
node *next[kind];//树每个节点的子节点 trie树的分支是128的
int cnt;//是否为该单词的最后一个节点
node()//构造函数初始化
{
fail=NULL;
cnt=0;
memset(next,NULL,sizeof(next));
}
};
char str[210];///输入的单词
char a[10010];///输入的模式串
queue<node*>qq;///队列构造失败指针
void BuildTree(node *root ,int index)//建Trie树
{
node *p=root;
int i=0,id;
while(str[i])
{
id=str[i];
if(p->next[id]==NULL)
p->next[id]=new node();
p=p->next[id];
i++;
}
(p->cnt)=index;///表示是一个单词的结尾
}
void bfs(node *root)///求失败指针
{
while(!qq.empty())
qq.pop();
root->fail=NULL;
qq.push(root);
root->fail=NULL;
node *tmp,*p;
while(!qq.empty())
{
tmp=qq.front();///拿到一个节点
qq.pop();
p=NULL;
for(int i=0; i<kind; i++)
{
if(tmp->next[i]!=NULL)
{
p=tmp->fail;
while(p&&!p->next[i])///p:当前点tmp不是根 !p->next[i]: 还能找到i这个字母在
p=p->fail;
if(!p)
tmp->next[i]->fail=root;
else
tmp->next[i]->fail=p->next[i];
qq.push(tmp->next[i]);
}
}
}
}
int has[600];
int Ac_run(node *root)
{
int i=0,ans=0,id;
node *p=root;
while(a[i])
{
id=a[i];
while(!p->next[id]&&p!=root)///p下面没有id字母
p=p->fail;
p=p->next[id];
if(!p)
p=root; ///while结束 如果是根的情况
node *tmp=p;
while(tmp!=root&&tmp->cnt!=-1)
{
///cnt=-1表示已经计算过
if(tmp->cnt!=0)
{
ans+=tmp->cnt;
has[tmp->cnt]=1;
}
tmp=tmp->fail;
}
i++;
}
return ans;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
node *root=new node();
for(int i=1; i<=n; i++)
{
scanf("%s",str);
BuildTree(root,i);
}
bfs(root);
int m;
scanf("%d",&m);
int total=0;
for(int i=1; i<=m; i++)
{
memset(has,0,sizeof(has));
scanf("%s",a);
if(Ac_run(root))
{
total++;
printf("web %d:",i);
for(int j=1; j<=n; j++)
{
if(has[j])
printf(" %d",j);
}
puts("");
}
}
printf("total: %d\n",total);
}
return 0;
}