所谓广义SAM,就是更广泛意义下的SAM
(逃)
前言
感觉字符串的理解难度的巅峰还是在SAM,广义SAM只是在套一些特判罢了,并不是太难理解。
可以解决多字符串的子串问题,几乎就是把SAM能做的东西从单串变成了多串。
解析
在线做法
有一个很流行的盗版做法是每次加入新串时把 lstlstlst 重新赋值为 111,然后就和正常SAM一样做。
但这会出现一些问题,就是当 translst,ctrans_{lst,c}translst,c 存在时,我们会加入空节点。
这里的空节点的具体含义是指其 minlen>maxlenminlen>maxlenminlen>maxlen,从而使得该结点代表的等价类没有任何字符串。
这个时候我们进行特判即可,后面还是按照正常SAM做。
struct SAM{int tr[N][26],fa[N],len[N],tot,lst;SAM(){tot=lst=1;}inline int ins(int c,int p){c-='a';if(tr[p][c]){int q=tr[p][c];if(len[q]==len[p]+1) return q;else{int nq=++tot;len[nq]=len[p]+1;fa[nq]=fa[q];for(int i=0;i<26;i++) tr[nq][i]=tr[q][i];fa[q]=nq;for(;p&&tr[p][c]==q;p=fa[p]) tr[p][c]=nq;return nq;}}else{int cur=++tot;len[cur]=len[p]+1;for(;p&&!tr[p][c];p=fa[p]) tr[p][c]=cur;if(!tr[p][c]) fa[cur]=1;else{int q=tr[p][c];if(len[q]==len[p]+1) fa[cur]=q;else{int nq=++tot;len[nq]=len[p]+1;fa[nq]=fa[q];for(int i=0;i<26;i++) tr[nq][i]=tr[q][i];fa[q]=fa[cur]=nq;for(;p&&tr[p][c]==q;p=fa[p]) tr[p][c]=nq;}}return cur;}}inline void addstring(char *s){int n=strlen(s+1),lst=1;for(int i=1;i<=n;i++) lst=ins(s[i],lst);return;}
}sam;
然而,这个做法对一棵 trietrietrie 树建SAM的时候复杂度是 O(G(T))O(G(T))O(G(T)) 的(G(T)G(T)G(T) 表示所有叶子的深度和),这在许多时候会被卡成 O(n2)O(n^2)O(n2),因此,我们需要寻找另一种做法。
离线做法
这个方法对于 trietrietrie 树建SAM的复杂度是优秀的 O(T)O(T)O(T)。
考虑bfs,从而使得深度单调不降。
每次取出队首,以它父亲在SAM上对应的结点 作为 lstlstlst 进行插入即可。由于 trietrietrie 树本身的性质,此时必然有 translst,c=NULLtrans_{lst,c}=NULLtranslst,c=NULL,因此直接按照正常的SAM写即可。
struct SAM{int tr[N][26],pos[N],len[N],fa[N],tot;SAM(){tot=1;}inline int ins(int c,int p){int cur=++tot;len[cur]=len[p]+1;for(;p&&!tr[p][c];p=fa[p]) tr[p][c]=cur;if(!tr[p][c]) fa[cur]=1;else{int q=tr[p][c];if(len[q]==len[p]+1) fa[cur]=q;else{int nq=++tot;len[nq]=len[p]+1;fa[nq]=fa[q];for(int i=0;i<26;i++) tr[nq][i]=tr[q][i];fa[q]=fa[cur]=nq;for(;p&&tr[p][c]==q;p=fa[p]) tr[p][c]=nq;}}return cur;}int q[N],st,ed;void build(){q[st=ed=1]=1;pos[1]=1;while(st<=ed){int now=q[st++];//pos[now]=ins(trie.col[now],pos[trie.fa[now]]);for(int i=0;i<26;i++){int to=trie.tr[now][i];if(to){q[++ed]=to;pos[to]=ins(trie.col[to],pos[now]);}}}return;}
}sam;