后缀自动机

理解起来好困难啊QAQ

WIKIOI3160 求两个串的最长公共子串

见CLJppt

 1 char s[maxn];
 2 struct sam
 3 {
 4     int n,last,cnt;
 5     int go[maxn][26],l[maxn],fa[maxn];
 6     void add(int x)
 7     {
 8         int p=last,np=last=++cnt;l[np]=l[p]+1;
 9         for(;p&&!go[p][x];p=fa[p])go[p][x]=np;
10         if(!p)fa[np]=1;
11         else 
12         {
13             int q=go[p][x];
14             if(l[p]+1==l[q])fa[np]=q;
15             else 
16             {
17                 int nq=++cnt;l[nq]=l[p]+1;
18                 memcpy(go[nq],go[q],sizeof(go[q]));
19                 fa[nq]=fa[q];
20                 fa[np]=fa[q]=nq;
21                 for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
22             }
23         }
24     }    
25     void init()
26     {
27         last=cnt=1;
28         scanf("%s",s);int m=strlen(s);
29         for0(i,m-1)add(s[i]-'a');
30     }
31     void solve()
32     {
33         scanf("%s",s);int m=strlen(s),now=1,t=0,ans=0;
34         for0(i,m-1)
35         {
36             int x=s[i]-'a';
37             if(go[now][x])t++,now=go[now][x];
38             else 
39             {
40                 while(now&&!go[now][x])now=fa[now];
41                 if(!now)t=0,now=1;
42                 else t=l[now]+1,now=go[now][x];
43             }
44             ans=max(ans,t);
45         }
46         printf("%d\n",ans);
47     }
48 }T;
49 int main()
50 {
51     T.init();
52     T.solve();
53     return 0;
54 }
View Code

BZOJ2555: SubString

正解是SAM+LCT,但出题人显然没有卡暴力。。。写了个暴力结果跑了rank4 233

犯了一个sb错就是没有更新lastQAQ

 1 char s[2*maxn];
 2 int mask;
 3 struct sam
 4 {
 5     int last,cnt,fa[maxn],go[maxn][26],l[maxn],r[maxn];
 6     sam(){last=cnt=1;}
 7     void add(int x)
 8     {
 9         int p=last,np=++cnt;last=np;l[np]=l[p]+1;
10         for(;p&&!go[p][x];p=fa[p])go[p][x]=np;
11         if(!p)fa[np]=1;
12         else
13         {
14             int q=go[p][x];
15             if(l[p]+1==l[q])fa[np]=q;
16             else
17             {
18                 int nq=++cnt;l[nq]=l[p]+1;
19                 memcpy(go[nq],go[q],sizeof(go[q]));
20                 r[nq]=r[q];
21                 fa[nq]=fa[q];
22                 fa[q]=fa[np]=nq;
23                 for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
24             }
25         }
26         for(;np;np=fa[np])r[np]++;
27     }
28     void insert(char s[])
29     {
30         int n=strlen(s),t=mask;
31         for0(i,n-1){mask=(mask*131+i)%n;swap(s[i],s[mask]);}
32         mask=t;
33         for0(i,n-1)add(s[i]-'A');
34     }
35     void query(char s[])
36     {
37         int n=strlen(s),now=1,t=mask;
38         for0(i,n-1){mask=(mask*131+i)%n;swap(s[i],s[mask]);}
39         for0(i,n-1)now=go[now][s[i]-'A'];
40         mask=t^r[now];
41         printf("%d\n",r[now]);
42     }
43 }T;
44 int main()
45 {
46     freopen("input.txt","r",stdin);
47     freopen("output.txt","w",stdout);
48     int Q=read();
49     scanf("%s",s);int n=strlen(s);for0(i,n-1)T.add(s[i]-'A');
50     while(Q--)
51     {
52         scanf("%s",s);
53         if(s[0]=='A'){scanf("%s",s);T.insert(s);}
54         else {scanf("%s",s);T.query(s);}
55     }
56     return 0;
57 }
View Code

BZOJ3238: [Ahoi2013]差异

后缀自动机其实反过来添加形成的parent树就是后缀树啦。

写出后缀树DFS一遍就ok啦  妈妈我会写后缀树啦

 1 struct sam
 2 {
 3     int cnt,last,fa[maxn],go[maxn][26],head[maxn],l[maxn],s[maxn],tot;ll ans;
 4     char ch[maxn];
 5     struct edge{int go,next;}e[maxn];
 6     void add(int x)
 7     {
 8         int p=last,np=last=++cnt;l[np]=l[p]+1;
 9         for(;p&&!go[p][x];p=fa[p])go[p][x]=np;
10         if(!p)fa[np]=1;
11         else
12         {
13             int q=go[p][x];
14             if(l[p]+1==l[q])fa[np]=q;
15             else
16             {
17                 int nq=++cnt;l[nq]=l[p]+1;
18                 memcpy(go[nq],go[q],sizeof(go[q]));
19                 fa[nq]=fa[q];
20                 fa[q]=fa[np]=nq;
21                 for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
22             }
23         }
24         s[np]=1;
25     }
26     void init()
27     {
28         last=cnt=1;
29         scanf("%s",ch);int n=strlen(ch);ans=(ll)(n-1)*n*(n+1)/2;
30         for3(i,n-1,0)add(ch[i]-'a');
31     }
32     void add(int x,int y)
33     {
34         e[++tot]=(edge){y,head[x]};head[x]=tot;
35     }
36     void dfs(int x)
37     {
38         for4(i,x)
39         {
40             dfs(y);
41             ans-=(ll)2*s[y]*s[x]*l[x];
42             s[x]+=s[y];
43         }
44     }
45     void work()
46     {
47         for1(i,cnt)add(fa[i],i);
48         dfs(1);
49         cout<<ans<<endl;
50     }
51 }T;
52 int main()
53 {
54     freopen("input.txt","r",stdin);
55     freopen("output.txt","w",stdout);
56     T.init();
57     T.work();
58     return 0;
59 }
View Code

BZOJ2946: [Poi2000]公共串

多个串的LCS。可以SA,也可以SAM。

我们对每个节点保留mx[i][j]表示到i节点j串最多匹配多长,每个串做的时候就取max,然后这个节点对答案的贡献是min(),最后ans取max。

 1 int n;
 2 struct sam
 3 {
 4     int last,cnt,l[maxn],fa[maxn],go[maxn][26],mx[maxn][5];
 5     char s[maxn];
 6     void add(int x)
 7     {
 8         int p=last,np=last=++cnt;l[np]=l[p]+1;
 9         for(;p&&!go[p][x];p=fa[p])go[p][x]=np;
10         if(!p)fa[np]=1;
11         else
12         {
13             int q=go[p][x];
14             if(l[p]+1==l[q])fa[np]=q;
15             else
16             {
17                 int nq=++cnt;l[nq]=l[p]+1;
18                 memcpy(go[nq],go[q],sizeof(go[q]));
19                 fa[nq]=fa[q];
20                 fa[q]=fa[np]=nq;
21                 for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
22             }
23         }
24     }
25     void insert()
26     {
27         last=cnt=1;
28         scanf("%s",s);int n=strlen(s);
29         for0(i,n-1)add(s[i]-'a');
30     }
31     void work(int k)
32     {
33         scanf("%s",s);int n=strlen(s),now=1,t=0;
34         for0(i,n-1)
35         {
36             int x=s[i]-'a';
37             if(go[now][x]){t++;now=go[now][x];}
38             else
39             {
40                 while(now&&!go[now][x])now=fa[now];
41                 if(!now){t=0;now=1;}
42                 else t=l[now]+1,now=go[now][x];
43             }
44             for(int j=now;j;j=fa[j])mx[j][k]=max(mx[j][k],t);
45         }
46     }
47     void print()
48     {
49         int ans=0;
50         for1(i,cnt)
51         {
52             int t=l[i];
53             for0(j,n-1)t=min(t,mx[i][j]);
54             ans=max(ans,t);
55         }
56         cout<<ans<<endl;
57     }
58 }T;            
59 int main()
60 {
61     freopen("input.txt","r",stdin);
62     freopen("output.txt","w",stdout);
63     n=read();
64     T.insert();
65     for0(i,n-1)T.work(i);
66     T.print();
67     return 0;
68 }
View Code

BZOJ3879: SvT

构建出后缀树来就和差异那题一样了。1A简直感人肺腑。

  1 int n,m,a[maxn],id[maxn],v[maxn],top,sta[maxn],dep[maxn];
  2 ll ans;
  3 struct sam
  4 {
  5     int last,cnt,l[maxn],fa[maxn],head[maxn],go[maxn][26],tot,ti,dfn[maxn],f[maxn][20];
  6     struct edge{int go,next;}e[maxn];
  7     char s[maxn];
  8     void add(int x,int y)
  9     {
 10         e[++tot]=(edge){y,head[x]};head[x]=tot;
 11     }
 12     int add(int x)
 13     {
 14         int p=last,np=last=++cnt;l[np]=l[p]+1;
 15         for(;p&&!go[p][x];p=fa[p])go[p][x]=np;
 16         if(!p)fa[np]=1;
 17         else
 18         {
 19             int q=go[p][x];
 20             if(l[p]+1==l[q])fa[np]=q;
 21             else
 22             {
 23                 int nq=++cnt;l[nq]=l[p]+1;
 24                 memcpy(go[nq],go[q],sizeof(go[q]));
 25                 fa[nq]=fa[q];
 26                 fa[q]=fa[np]=nq;
 27                 for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
 28             }
 29         }
 30         return np;
 31     }
 32     int lca(int x,int y)
 33     {
 34         if(dep[x]<dep[y])swap(x,y);
 35         int t=dep[x]-dep[y];
 36         for0(i,18)if(t>>i&1)x=f[x][i];
 37         if(x==y)return x;
 38         for3(i,18,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
 39         return f[x][0];
 40     }
 41     void dfs(int x)
 42     {
 43         dfn[x]=++ti;
 44         for1(i,18)if(dep[x]>=1<<i)f[x][i]=f[f[x][i-1]][i-1];else break;
 45         for4(i,x)
 46         {
 47           dep[y]=dep[x]+1;f[y][0]=x;
 48           dfs(y);
 49         }
 50     }
 51     void init()
 52     {
 53         last=cnt=1;
 54         scanf("%s",s+1);int n=strlen(s+1);
 55         for3(i,n,1)id[i]=add(s[i]-'a');
 56         for1(i,cnt)add(fa[i],i);
 57         dfs(1);
 58     }
 59 }T;
 60 struct graph
 61 {
 62     int head[maxn],tot,s[maxn];
 63     struct edge{int go,next;}e[maxn];
 64     void add(int x,int y)
 65     {
 66         e[++tot]=(edge){y,head[x]};head[x]=tot;
 67     }
 68     void dfs(int x)
 69     {
 70         s[x]=v[x];
 71         for4(i,x)
 72         {
 73             dfs(y);
 74             ans+=(ll)s[x]*s[y]*T.l[x];
 75             s[x]+=s[y];
 76         }
 77         head[x]=0;
 78     }
 79 }G;
 80 inline bool cmp(int x,int y){return T.dfn[x]<T.dfn[y];}
 81 int main()
 82 {
 83     freopen("input.txt","r",stdin);
 84     freopen("output.txt","w",stdout);
 85     n=read();m=read();
 86     T.init();
 87     while(m--)
 88     {
 89         int k=read();
 90         for1(i,k)a[i]=id[read()];
 91         sort(a+1,a+k+1,cmp);
 92         for1(i,k)v[a[i]]=1;
 93         sta[top=1]=1;G.tot=0;
 94         for1(i,k)
 95         {
 96             int x=a[i],f=T.lca(sta[top],x);
 97             while(dep[f]<dep[sta[top]])
 98             {
 99                 if(dep[f]>=dep[sta[top-1]])
100                 {
101                     G.add(f,sta[top--]);
102                     if(sta[top]!=f)sta[++top]=f;
103                     break;
104                 }
105                 G.add(sta[top-1],sta[top]);top--;
106             }
107             if(sta[top]!=x)sta[++top]=x;
108         }
109         while(--top)G.add(sta[top],sta[top+1]);
110         ans=0;
111         G.dfs(1);
112         printf("%I64d\n",ans);
113         for1(i,k)v[a[i]]=0;
114     }      
115     return 0;
116 }
View Code

2780: [Spoj]8093 Sevenk Love Oimaster

给出n个串,在给出m个询问,每次询问一个串s在给出的n个串中多少个串中出现了.

好像后缀数组也能做?跑出sa,然后二分出左右端点,再上一次 hill的项链?估计也不会好写到哪里去...(就是不知道能不能建出SA)

还是说SAM做法。

所谓广义后缀自动机,就是多个串的后缀自动机。具体构建方法为了不存在两个串首尾相接构成新的串的情况,每加入一个串,我们就让last=root。

然后往下走的时候如果已经有出边了{l[go[last][x]]==l[last]+1那么就直接last=go[last][x],否则新建一个节点balabala。}否则还按原来的来。

然后因为一个节点有可能属于不同的串。所以我们要在后面挂链表。

那么我们对每个询问串从root沿着出边走,结束的时候在parent树中它在子树中的任意一个串中都出现了。这样问题就成了多次询问一个区间内有多少个不同的数字了。

@SDOI2009HH的项链

第一次感觉自己的代码写的好丑TAT

  1 struct graph
  2 {
  3     int tot,head[maxn];
  4     struct edge{int go,next;}e[maxn];
  5     void add(int x,int y)
  6     {
  7         e[++tot]=(edge){y,head[x]};head[x]=tot;
  8     }
  9 }A,B;
 10 int s[maxn],n,m,pos[maxn];
 11 struct rec{int x,y,id;}a[maxn];
 12 struct sam
 13 {
 14     int cnt,last,l[maxn],id[maxn][2],fa[maxn],ti;
 15     map<int,int>go[maxn];
 16     char s[maxn];
 17     sam(){cnt=1;}
 18     void add(int x,int y)
 19     {
 20         int p=last,q;
 21         if(q=go[p][x])
 22         {
 23             if(l[p]+1==l[q])last=q;
 24             else 
 25             {
 26                 int nq=++cnt;l[nq]=l[p]+1;
 27                 go[nq]=go[q];
 28                 fa[nq]=fa[q];
 29                 fa[q]=nq;
 30                 for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
 31                 last=nq;
 32             }
 33         }else
 34         {
 35             int np=++cnt;l[np]=l[p]+1;
 36             for(;p&&!go[p][x];p=fa[p])go[p][x]=np;
 37             if(!p)fa[np]=1;
 38             else
 39             {
 40                 q=go[p][x];
 41                 if(l[p]+1==l[q])fa[np]=q;
 42                 else
 43                 {
 44                     int nq=++cnt;l[nq]=l[p]+1;
 45                     go[nq]=go[q];
 46                     fa[nq]=fa[q];
 47                     fa[q]=fa[np]=nq;
 48                     for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
 49                 }
 50             }
 51             last=np;
 52         }
 53         B.add(last,y);//printf("%d %d\n",last,y);
 54     }
 55     void dfs(int x)
 56     {
 57         id[x][0]=++ti;pos[ti]=x;
 58         for4(A,i,x)dfs(y);
 59         id[x][1]=ti;
 60     }
 61     void insert(int y)
 62     {
 63         last=1;
 64         scanf("%s",s);int n=strlen(s);
 65         for0(i,n-1)add(s[i],y);
 66     }
 67     void work()
 68     {
 69         for1(i,cnt)A.add(fa[i],i);
 70         dfs(1);
 71     }
 72     rec find(int j)
 73     {
 74         scanf("%s",s);int n=strlen(s),now=1;
 75         for0(i,n-1)now=go[now][s[i]];
 76         return now?(rec){id[now][0],id[now][1],j}:(rec){2,1,j};
 77     }
 78 }T;
 79 void update(int x,int y)
 80 {    
 81     //printf("%d %d\n",x,y);
 82     for(;x<=T.cnt;x+=x&(-x))s[x]+=y;
 83 }
 84 int sum(int x)
 85 {
 86     int t=0; 
 87     for(;x;x-=x&(-x))t+=s[x];
 88     //cout<<x<<' '<<t<<endl;
 89     return t;
 90 }
 91 int v[maxn],ans[maxn];
 92 inline bool cmp(rec a,rec b){return a.y<b.y;}
 93 int main()
 94 {
 95     freopen("input.txt","r",stdin);
 96     freopen("output.txt","w",stdout);
 97     n=read();m=read();
 98     for1(i,n)T.insert(i);
 99     T.work();
100     for1(i,m)a[i]=T.find(i);
101     sort(a+1,a+m+1,cmp);
102     //for1(i,m)cout<<i<<' '<<a[i].x<<' '<<a[i].y<<' '<<a[i].id<<endl;
103     int now=1;
104     for1(i,T.cnt)
105     {
106         for4(B,j,pos[i])
107          {
108             if(v[y])update(v[y],-1);
109             v[y]=i;
110             update(v[y],1);
111          }
112         //cout<<i<<' '<<a[now].x<<' '<<a[now].y<<' '<<a[now].id<<endl;
113         while(a[now].y==i)ans[a[now].id]=sum(a[now].y)-sum(a[now].x-1),now++;
114     }
115     for1(i,m)printf("%d\n",ans[i]);    
116     return 0;
117 }
View Code

3473: 字符串

给出n个串,问每个串有多少个子串在至少k个串中都出现了。

类似于上一题,我们可以用“项链”的方法离线求出所有节点所代表的字符串的集合在多少个字符串中出现过。

如果他的出现次数>=k次,那么他对答案的贡献是l[i]-l[fa[i]]然后一个后缀对答案的总贡献就是他到根节点的权值和。然后再预处理一下就可以了。

修改了一下代码感觉美观多了

  1 int n,last,cnt=1,ti,k;
  2 typedef int arr[maxn];
  3 arr l,fa,s,f,pos,a,v;
  4 int go[maxn][26],id[maxn][2];
  5 char ch[maxn];
  6 struct graph
  7 {
  8     int tot,head[maxn];
  9     struct edge{int go,next;}e[maxn];
 10     inline void add(int x,int y)
 11     {
 12         e[++tot]=(edge){y,head[x]};head[x]=tot;
 13     }
 14 }A,B,C;
 15 inline void add(int x)
 16 {
 17     int p=last,q;
 18     if(q=go[p][x])
 19     {
 20         if(l[p]+1==l[q])last=q;
 21         else
 22         {
 23             int nq=++cnt;l[nq]=l[p]+1;
 24             memcpy(go[nq],go[q],sizeof(go[q]));
 25             fa[nq]=fa[q];
 26             fa[q]=nq;
 27             for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
 28             last=nq;
 29         }
 30     }else
 31     {
 32         int np=++cnt;l[np]=l[p]+1;
 33         for(;p&&!go[p][x];p=fa[p])go[p][x]=np;
 34         if(!p)fa[np]=1;
 35         else
 36         {
 37             q=go[p][x];
 38             if(l[p]+1==l[q])fa[np]=q;
 39             else
 40             {
 41                 int nq=++cnt;l[nq]=l[p]+1;
 42                 memcpy(go[nq],go[q],sizeof(go[q]));
 43                 fa[nq]=fa[q];
 44                    fa[q]=fa[np]=nq;
 45                 for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
 46             }
 47         }
 48         last=np;
 49     }
 50 }
 51 inline void dfs(int x)
 52 {
 53     id[x][0]=++ti;pos[ti]=x;
 54     for4(C,i,x)dfs(y);
 55     id[x][1]=ti;
 56 }
 57 inline void dfs2(int x)
 58 {
 59     for4(C,i,x)f[y]+=f[x],dfs2(y);
 60 }
 61 inline void update(int x,int y)
 62 {
 63     for(;x<=cnt;x+=x&(-x))s[x]+=y;
 64 }
 65 inline int sum(int x)
 66 {
 67     int t=0;
 68     for(;x;x-=x&(-x))t+=s[x];
 69     return t;
 70 }
 71 inline bool cmp(int x,int y){return id[x][1]<id[y][1];}
 72 int main()
 73 {
 74     freopen("input.txt","r",stdin);
 75     freopen("output.txt","w",stdout);
 76     n=read();k=read();
 77     for1(i,n)
 78     {
 79         last=1;
 80         scanf("%s",ch);int m=strlen(ch);
 81         for0(j,m-1)add(ch[j]-'a'),A.add(last,i),B.add(i,last);
 82     }
 83     for1(i,cnt)C.add(fa[i],i);
 84     dfs(1);
 85     for1(i,cnt)a[i]=i;
 86     sort(a+1,a+cnt+1,cmp);
 87     int now=1;
 88     for1(i,cnt)
 89     {
 90         for4(A,j,pos[i])
 91         {
 92             if(v[y])update(v[y],-1);
 93             v[y]=i;
 94             update(v[y],1);
 95         }    
 96         while(id[a[now]][1]==i)f[a[now]]=(sum(id[a[now]][1])-sum(id[a[now]][0]-1))>=k?l[a[now]]-l[fa[a[now]]]:0,now++;
 97     }
 98     dfs2(1);
 99     for1(i,n)
100     {
101         ll ans=0;
102         for4(B,j,i)ans+=f[y];
103         printf("%lld",ans);if(i!=n)printf(" ");
104     }
105     return 0;
106 }
View Code

 

3926: [Zjoi2015]诸神眷顾的幻想乡

[捂脸熊]没想到这题这么简单233 因为叶子很少,所以直接枚举所有的叶子把从他开始dfs顺便建立建立广义自动机,然后求本质不同的字符串的个数。然后就完了。。。

 1 int n,k,tot,cnt,last;
 2 typedef int arr[maxn];
 3 arr fa,l,head,du,a;
 4 int go[maxn][12];
 5 struct edge{int go,next;}e[maxn];
 6 inline void add(int x,int y)
 7 {
 8     e[++tot]=(edge){y,head[x]};head[x]=tot;du[x]++;
 9     e[++tot]=(edge){x,head[y]};head[y]=tot;du[y]++;
10 }
11 inline void add(int x)
12 {
13     int p=last,q;
14     if(q=go[p][x])
15     {
16         if(l[p]+1==l[q])last=q;
17         else
18         {
19             int nq=++cnt;l[nq]=l[p]+1;
20             memcpy(go[nq],go[q],sizeof(go[q]));
21             fa[nq]=fa[q];
22             fa[q]=nq;
23             for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
24             last=nq;
25         }
26     }else
27     {
28         int np=++cnt;l[np]=l[p]+1;
29         for(;p&&!go[p][x];p=fa[p])go[p][x]=np;
30         if(!p)fa[np]=1;
31         else
32         {
33             q=go[p][x];
34             if(l[p]+1==l[q])fa[np]=q;
35             else
36             {
37                 int nq=++cnt;l[nq]=l[p]+1;
38                 memcpy(go[nq],go[q],sizeof(go[q]));
39                 fa[nq]=fa[q];
40                    fa[q]=fa[np]=nq;
41                 for(;p&&go[p][x]==q;p=fa[p])go[p][x]=nq;
42             }
43         }
44         last=np;
45     }
46 }
47 inline void dfs(int x,int f,int z)
48 {
49     add(a[x]);
50     int t=last;
51     for4(i,x)if(y!=f){dfs(y,x,last);last=t;}
52 }
53 int main()
54 {
55     freopen("input.txt","r",stdin);
56     freopen("output.txt","w",stdout);
57     n=read();k=read();
58     for1(i,n)a[i]=read();
59     for1(i,n-1)add(read(),read());
60     cnt=1;
61     for1(i,n)if(du[i]==1)dfs(i,0,last=1);
62     ll ans=0;
63     for1(i,cnt)ans+=l[i]-l[fa[i]];
64     cout<<ans<<endl;
65     return 0; 
66 }
View Code

 

posted @ 2015-04-07 00:07  ZYF-ZYF  Views(935)  Comments(12Edit  收藏  举报