//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;
}
 posted on 2017-09-22 17:05  cylcy  阅读(147)  评论(0编辑  收藏  举报