//hdu6096 AC自动机
/*
参照了:http://blog.csdn.net/calabash_boy/article/details/77101529
利用一个很巧妙的方法将这道题目转化为AC自动机题
对于每组前缀和后缀,将他们拼成后缀+'#'+前缀的字符串,
将所有这些组当成模式串并用AC自动机预处理。
对于每个输入的字典单词,把它转化成单词+'#'+单词的字符串,
把新的字符串当做目标串跑一遍即可。
注意模式串会有重复,所以要在每个trie树节点用一个vector保存对应的模式串数组下标,
另外用一个weight记录这个单词被匹配了多少次,最后一并统计(而不是每次都访问vector里
的下标并将对应位置加1,这样会超时。。)
#号的使用非常重要,可以把它理解为一个位置固定器,使得新生成的模式串
一旦被匹配,其前半部分即‘后缀’一定是在新目标串的#号前被匹配,而后半部分即
后缀一定是在新目标串的#号后面被匹配。例如:
原目标串:cab 新目标串: cab#cab
原模式串前缀和后缀:a c 新模式串:c#a
可以很明显看出,新目标串和新模式串是匹配不上的。
但假如去掉#号,
新目标串: cabcab
新模式串:ca
这里虽然能匹配上,但肯定是不正确的,因为匹配的位置不是我们希望匹配的位置。
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <map>
#include <bitset>
using namespace std;
#define ll long long
#define fr(i,a,b) for(int i=a;i<=b;i++)
#define frr(i,a,b) for(int i=a;i>=b;i--)
#define ms(a,b) memset(a,b,sizeof(a))
#define scfd(a) scanf("%d",a)
#define scflf(a) scanf("%lf",a)
#define scfs(a) scanf("%s",a)
#define ptfd(a) printf("%d\n",a)
#define ptfs(a) printf("%s\n",a)
#define showd(a,b) printf(a"=%d\n",b)
#define showlf(a,b) printf(a"=%lf\n",b)
#define shows(a,b) printf(a"=%s\n",b)
#define mmcp(a,b) memcpy(a,b,sizeof(b))
#define pb(a) push_back(a)
const int MAXN=100005;
int len[MAXN],plen[MAXN],ans[MAXN];
int cases,nd,nq;
vector<char>dic[MAXN];
char s[MAXN*5];
char pre[MAXN*5],suf[MAXN*5];
struct node{
int ch[30];
char c;
bool end;
int fail;
int last;//suffix link
int wei;
vector<int>id;//previous
node(){
ms(ch,0);
end=false;
wei=last=fail=0;
}
};
struct trie{
node nd[500005];
int size;
trie(){
nd[0].fail=-1;
size=1;
}
void init(){
size=1;
fr(i,0,500004){
ms(nd[i].ch,0);
nd[i].end=false;
nd[i].wei=nd[i].last=nd[i].fail=0;
nd[i].id.clear();
}
nd[0].fail=-1;
}
int idx(char a){
if(a=='#')
return 26;
return a-'a';
}
void push(char *s,int idd){
int l=strlen(s);
int nnd,nc;
nnd=nc=0;
while(nd[nnd].ch[idx(s[nc])]&&nc<l){
if(nc==l-1){
nd[nd[nnd].ch[idx(s[nc])]].end=true;
nd[nd[nnd].ch[idx(s[nc])]].id.pb(idd);
}
nnd=nd[nnd].ch[idx(s[nc])],nc++;
}
while(nc<l){
nd[nnd].ch[idx(s[nc])]=size;
node t;
t.c=s[nc];
if(nc==l-1)
t.end=true,t.id.pb(idd);
nd[size++]=t;
nnd=nd[nnd].ch[idx(s[nc])],nc++;
}
}
};
struct ac_autometa{
trie tr;
char t[MAXN*2];
int pl;//previous
void init(){
tr.nd[0].fail=-1;
queue<int>q;
q.push(0);
while(!q.empty()){
int nnd=q.front();
q.pop();
fr(i,0,26)
if(tr.nd[nnd].ch[i]){
int son=tr.nd[nnd].ch[i];
int faf=tr.nd[nnd].fail;
while(faf!=-1&&!tr.nd[faf].ch[i])
faf=tr.nd[faf].fail;
if(faf!=-1){
tr.nd[son].fail=tr.nd[faf].ch[i];
tr.nd[son].last=tr.nd[tr.nd[faf].ch[i]].end?tr.nd[faf].ch[i]:tr.nd[tr.nd[faf].ch[i]].last;
}
q.push(son);
}
}
}
void match(){
int l=strlen(t);
int nnd=0;
fr(i,0,l-1){
while(nnd!=-1&&!tr.nd[nnd].ch[tr.idx(t[i])])
nnd=tr.nd[nnd].fail;
if(nnd==-1)
nnd=0;
else
nnd=tr.nd[nnd].ch[tr.idx(t[i])];
int x=nnd;
while(x!=0){
if(tr.nd[x].end){
int tl=tr.nd[x].id.size();
if(len[tr.nd[x].id[0]]<=pl)
tr.nd[x].wei++;
}
x=tr.nd[x].last;
}
}
}
}aho;
int main(){
scanf("%d",&cases);
while(cases--){
ms(ans,0);
aho.tr.init();
scanf("%d%d",&nd,&nq);
fr(i,1,nd){
scfs(s);
int l=strlen(s);
plen[i]=l;
s[l]='#';
fr(j,l+1,l*2)
s[j]=s[j-l-1];
fr(j,0,l*2)
dic[i].pb(s[j]);
}
fr(i,1,nq){
scfs(pre);
scfs(suf);
int lp=strlen(pre),ls=strlen(suf);
len[i]=lp+ls;
fr(j,0,ls-1)
s[j]=suf[j];
s[ls]='#';
fr(j,0,lp-1)
s[j+ls+1]=pre[j];
s[ls+lp+1]='\0';
aho.tr.push(s,i);
}
aho.init();
fr(i,1,nd){
fr(j,0,dic[i].size()-1)
aho.t[j]=dic[i][j];
aho.t[dic[i].size()]='\0';
aho.pl=plen[i];
aho.match();
}
fr(i,0,aho.tr.size-1){
if(aho.tr.nd[i].end&&aho.tr.nd[i].wei){
int k=aho.tr.nd[i].id.size();
fr(j,0,k-1)
ans[aho.tr.nd[i].id[j]]+=aho.tr.nd[i].wei;
}
}
fr(i,1,nq)
ptfd(ans[i]);
fr(i,1,nd)
dic[i].clear();
}
return 0;
}