2780: [Spoj]8093 Sevenk Love Oimaster
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 738 Solved: 257
[ Submit][ Status][ Discuss]
Description
Oimaster and sevenk love each other.
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
abcabcabc
aaa
aafe
abc
a
ca
Sample Output
1
3
1
3
1
HINT
Source
题解:广义后缀自动机
题目大意:给出n个原串,再给出m个查询串。求每个查询串出现在了多少原串中。
建立后缀自动机,所谓广义就是将几个串建立在同一个自动机上,每次加入一个新串的时候,将last恢复到root,然后其他照常做就可以了。
如何统计每个状态出现在了多少原串中呢?我们对于每个状态维护两个值size,nxt。nxt存储的是上一个到达这个状态的串是哪个原串,如果与当前的原串相同就不更新。如果不相同就size++.根据后缀自动机的性质,当前点的值改变,parent链上的信息都需要更改,链上nxt的值应该是区间分布的,所以只要找到一个nxt等于当前的点,就可以不用再往前找了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200003
using namespace std;
int ch[N][30],fa[N],l[N],n,m,len;
int r[N],v[N],cnt,np,p,nq,q,last,root,nxt[N],now,size[N];
char s[N];
void extend(int x)
{
int c=s[x]-'a';
p=last; np=++cnt; last=np;
l[np]=l[p]+1;
for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if (!p) fa[np]=root;
else {
q=ch[p][c];
if (l[q]==l[p]+1) fa[np]=q;
else {
nq=++cnt; l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[nq]); size[nq]=size[q]; nxt[nq]=nxt[q];
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
for (;np;np=fa[np])
if (nxt[np]!=now) {
size[np]++;
nxt[np]=now;
}
else break;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
root=++cnt;
for(int i=1;i<=n;i++) {
scanf("%s",s+1);
last=root;
len=strlen(s+1);
now=i;
for (int j=1;j<=len;j++)
extend(j);
}
for (int i=1;i<=m;i++) {
scanf("%s",s+1);
len=strlen(s+1);
p=root;
for (int j=1;j<=len;j++) p=ch[p][s[j]-'a'];
printf("%d\n",size[p]);
}
}