【BZOJ2780】 Sevenk Love Oimaster
题意:
有 \(n\) 个大串和 \(m\) 个询问,每次给出一个字符串 \(s\) 询问在多少个大串中出现过
Solution:
广义后缀自动机常用于对于多个串的子串分别进行匹配。实现也很简单,只要在新加一个串的时候将 \(last\) 置为 \(1\) 即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
const int N=200005;
int pre[N],len[N],size[N],ch[N][30],lst,cnt=1,n,q,vis[N],tms[N];
string s[N],s1;
void extend(int c)
{
int p=lst,np=++cnt;lst=np;
len[np]=len[p]+1,size[np]=1;
for(;p&&!ch[p][c];p=pre[p]) ch[p][c]=np;
if(!p) {
pre[np]=1;
return ;
}
int q=ch[p][c];
if(len[p]+1==len[q]) {
pre[np]=q;
return ;
}
int nq=++cnt;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
pre[nq]=pre[q],pre[q]=pre[np]=nq;
for(;ch[p][c]==q;p=pre[p])ch[p][c]=nq;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("2103.in","r",stdin);
#else
ios::sync_with_stdio(false);
#endif
cin>>n>>q;
for(int i=1;i<=n;++i)
{
cin>>s[i],lst=1;
for(int j=0;j<s[i].size();++j) extend(s[i][j]-'a');
}
for(int i=1;i<=n;++i)
for(int j=0,now=1;j<s[i].size();++j)
{
now=ch[now][s[i][j]-'a'];
int tmp=now;
for(;tmp&&vis[tmp]!=i;tmp=pre[tmp]) ++tms[tmp],vis[tmp]=i;
}
while(q--)
{
cin>>s1;
int now=1;
for(int i=0;i<s1.size();++i) now=ch[now][s1[i]-'a'];
cout<<tms[now]<<endl;
}
}