传送门biu~
存一下每个模式串的结尾在AC自动机上的哪个节点,用目标串在AC自动机上匹配的时候把能匹配到的点打上标记,最后从每个模式串结尾沿着->fa一直向根爬,遇见的第一个被打标记的点就是能匹配的最长前缀。
Duan2baka大佬说AC自动机不建Trie图就是在Trie树上暴力。。的确建Trie图要优越的多。
#include<bits/stdc++.h>
using namespace std;
inline int Hash(char c){
switch(c){
case 'E': return 0;
case 'S': return 1;
case 'W': return 2;
case 'N': return 3;
}
}
struct Node{
Node *ch[4],*nex,*fa;
int dep;bool b;
Node(){
nex=fa=NULL;dep=0;
for(int i=0;i<4;++i) ch[i]=NULL;
}
}*root=new Node,*tail[100005];
queue<Node*>q;
int n,m;char s[10000005],c[105];
inline void Insert(char c[],int id){
Node *x=root;
for(int i=1;c[i];++i){
int to=Hash(c[i]);
if(!x->ch[to]) x->ch[to]=new Node,x->ch[to]->fa=x,x->ch[to]->dep=x->dep+1;
x=x->ch[to];
}
tail[id]=x;
}
inline void GetFail(){
for(int i=0;i<4;++i){
if(root->ch[i]) q.push(root->ch[i]),root->ch[i]->nex=root;
else root->ch[i]=root;
}
while(!q.empty()){
Node *x=q.front();q.pop();
for(int i=0;i<4;++i){
if(x->ch[i]) q.push(x->ch[i]),x->ch[i]->nex=x->nex->ch[i];
else x->ch[i]=x->nex->ch[i];
}
}
}
inline void Match(char s[]){
Node *x=root;x->b=true;
for(int i=1;s[i];++i){
x=x->ch[Hash(s[i])];
Node *tmp=x;
while(!tmp->b) tmp->b=true,tmp=tmp->nex;
}
}
int main(){
scanf("%d%d%s",&n,&m,s+1);
for(int i=1;i<=m;++i){
scanf("%s",c+1);
Insert(c,i);
}
GetFail();Match(s);
for(int i=1;i<=m;++i){
Node *x=tail[i];
while(!x->b) x=x->fa;
printf("%d\n",x->dep);
}
return 0;
}