【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;
	}
}
posted @ 2019-02-27 22:49  x_faraway_x  阅读(123)  评论(0)    收藏  举报