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

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

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define N (201000)
 5 using namespace std;
 6 
 7 int n,m,l[N],r[N];
 8 char s[N<<2],t[N<<1];
 9 
10 struct SAM
11 {
12     int son[N][28],fa[N],step[N],size[N],vis[N];
13     int p,q,np,nq,last,cnt;
14     SAM(){last=cnt=1;}
15 
16     void Insert(int x)
17     {
18         p=last; np=last=++cnt; step[np]=step[p]+1;
19         while (p && !son[p][x]) son[p][x]=np, p=fa[p];
20         if (!p) fa[np]=1;
21         else
22         {
23             q=son[p][x];
24             if (step[q]==step[p]+1) fa[np]=q;
25             else
26             {
27                 nq=++cnt; step[nq]=step[p]+1;
28                 memcpy(son[nq],son[q],sizeof(son[q]));
29                 fa[nq]=fa[q]; fa[q]=fa[np]=nq;
30                 while (son[p][x]==q) son[p][x]=nq,p=fa[p];
31             }
32         }
33     }
34     void Calc()
35     {
36         for (int i=1; i<=n; ++i)
37         {
38             int now=1;
39             for (int j=l[i]; j<r[i]; ++j)
40             {
41                 now=son[now][s[j]-'a'];
42                 int t=now;
43                 while (t && vis[t]!=i) vis[t]=i,++size[t],t=fa[t];
44             }
45         }
46     }
47     void Find(char s[])
48     {
49         int now=1;
50         for (int j=0,l=strlen(s); j<l; ++j)
51             now=son[now][s[j]-'a'];
52         printf("%d\n",size[now]);
53     }
54 }SAM;
55 
56 int main()
57 {
58     scanf("%d%d",&n,&m);
59     for (int i=1; i<=n; ++i)
60     {
61         scanf("%s",s+r[i-1]); int len=strlen(s+r[i-1]);
62         l[i]=r[i-1], r[i]=l[i]+len;
63     }
64     for (int i=1; i<=n; ++i,SAM.last=1)
65         for (int j=l[i]; j<r[i]; ++j)
66             SAM.Insert(s[j]-'a');
67     SAM.Calc();
68     for (int i=1; i<=m; ++i)
69         scanf("%s",t),SAM.Find(t);
70 }
posted @ 2018-11-25 18:48  Refun  阅读(252)  评论(0编辑  收藏  举报