BZOJ2780:[SPOJ8093]Sevenk Love Oimaster(广义SAM)

时间:2024-01-05 15:31:44

Description

Oimaster and sevenk love each other.
But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster.As a woman's nature, sevenk felt angry and began to check oimaster's online talk with ChuYuXun.    
Oimaster talked with ChuYuXun n times, and each online talk actually is a string.Sevenk asks q questions like this,    "how many strings in oimaster's online talk contain this string as their substrings?"
有n个大串和m个询问,每次给出一个字符串s询问在多少个大串中出现过

Input

There are two integers in the first line, 
the number of strings n and the number of questions q.
And n lines follow, each of them is a string describing oimaster's online talk. 
And q lines follow, each of them is a question.
n<=10000, q<=60000 
the total length of n strings<=100000, 
the total length of q question strings<=360000

Output

For each question, output the answer in one line.

Sample Input

3 3
abcabcabc
aaa
aafe
abc
a
ca

Sample Output

1
3
1

Solution

先把大串的广义$SAM$建出来,然后用$n$个大串在$SAM$上跑。每个点开一个$vis[i]$和$size[i]$,存这个点上一次被哪个大串访问,这个点一共被几个大串访问过。

同时每访问一个点,就要沿着这个点的$fa$指针往上暴跳,更新$vis$,同时$size+1$。直到跳到一个$vis$是当前大串的点就停止。

答案就是用询问串在$SAM$上跑,终点的$size$值。

还有一个$nlogn$的做法我不会QAQ

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#define N (201000)
using namespace std; int n,m,l[N],r[N];
char s[N<<],t[N<<]; struct SAM
{
int son[N][],fa[N],step[N],size[N],vis[N];
int p,q,np,nq,last,cnt;
SAM(){last=cnt=;} void Insert(int x)
{
p=last; np=last=++cnt; step[np]=step[p]+;
while (p && !son[p][x]) son[p][x]=np, p=fa[p];
if (!p) fa[np]=;
else
{
q=son[p][x];
if (step[q]==step[p]+) fa[np]=q;
else
{
nq=++cnt; step[nq]=step[p]+;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
while (son[p][x]==q) son[p][x]=nq,p=fa[p];
}
}
}
void Calc()
{
for (int i=; i<=n; ++i)
{
int now=;
for (int j=l[i]; j<r[i]; ++j)
{
now=son[now][s[j]-'a'];
int t=now;
while (t && vis[t]!=i) vis[t]=i,++size[t],t=fa[t];
}
}
}
void Find(char s[])
{
int now=;
for (int j=,l=strlen(s); j<l; ++j)
now=son[now][s[j]-'a'];
printf("%d\n",size[now]);
}
}SAM; int main()
{
scanf("%d%d",&n,&m);
for (int i=; i<=n; ++i)
{
scanf("%s",s+r[i-]); int len=strlen(s+r[i-]);
l[i]=r[i-], r[i]=l[i]+len;
}
for (int i=; i<=n; ++i,SAM.last=)
for (int j=l[i]; j<r[i]; ++j)
SAM.Insert(s[j]-'a');
SAM.Calc();
for (int i=; i<=m; ++i)
scanf("%s",t),SAM.Find(t);
}