SPOJ8093Sevenk Love Oimaster(广义后缀自动机)

 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?"
 
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

题意:

给定一些模板串,询问每个匹配串在多少个模板串里出现过。

思路:

     后缀数组办法:

       全部模板串连接在一起SA排序,SA数组附件的串里面去验证原串,还没写,我说不清楚,大概是后缀数组+RMQ处理。

      后缀自动机办法:

       1,广义后缀自动机+dfs序列+。。。

       2,后缀自动机+标记,对于每个新的后缀集合np,标记它最近出现的原串,对每个模板串出现的新串的数量++。(目前发现最快的版本,如下)

经验:

  • 与普通的后缀自动机不同的是,广义后缀自自动机在加入一个新串的时候,从root开始。
  • 为了记录每个状态在哪些串出现过,会在每个np向上传递,我的代码是用的没加一个字符,向上传递一次。也可以用bitset记录在哪里出现过等到加完所有字符串后再拓扑排序,然后“亦或”向上传递。
#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()
{
    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
",size[p]);
    }
}
原文地址:https://www.cnblogs.com/hua-dong/p/8024294.html