首页 > 其他分享 >【模板】广义后缀自动机 exSAM

【模板】广义后缀自动机 exSAM

时间:2022-11-06 19:37:37浏览次数:78  
标签:exSAM ch 后缀 字符串 tail endpos fail cq 模板

posted on 2022-11-02 18:51:48 | under 模板 | source

solution

膜拜 @xzzduang。

我们重学一个 SAM。

一个点维护的是所有 \(endpos=S\) 的(本质不同的)串,显然这些串的长度连续,我们记最长的长度为 \(len_u\)。

从根节点出发,到达点 \(u\) 的所有路径组成的字符串就是点 \(u\) 维护的字符串。

什么是转移边 / 出边 \(ch_{u,i}\)?表示在点 \(u\) 维护的字符串后面加上字符 \(a\)。

什么是后缀链接 \(link_u\)(务必与 AC 自动机上的 \(fail\) 区分)?就是点 \(u\) 维护的最短的串砍掉一段前缀后的一个新的等价类。长度一定是连续的,因此我们说点 \(u\) 维护的子串的最短长度是 \(len_{link_u}+1\),最长的是 \(len_u\)。

注意结论:对于一个字符串,你加长它会使等价类变小,缩短它会使等价类变长。

结论:一个点 \(u\) 的真实的 \(endpos\) 是它 \(fail\) 子树中的所有 \(endpos\) 的并。

现在开始增量构造。假如我们有一个 \(tail\) 表示上一次加入的那个整串。加入字符 \(r\),新开一个 \(u\) 表示新的整串。时刻记住,我们要维护出边和后缀链接。

显然 \(ch_{tail,r}=u\),从 \(tail\) 往上跳 \(link\) 到 \(p\),这是在砍掉前缀,如果 \(ch_{t,r}=\varnothing\) 那么接上 \(ch_{p,r}=u\)。

如果 \(ch_{p,r}\neq\varnothing\),因为我们在砍前缀,再砍它的出边也存在,所以我们在这里停下来更新。令 \(q=ch_{p,r}\)。我们很天真地想要 \(fail_u=q\),这不好。

对于一个出现位置,有颜色的部分,是可能的子串左端点。显然 \(p\) 在这里面。如果 \(p\) 刚好是 \(q\) 的最短的字符串(绿色部分),那么直接 \(fail_u=q\) 是正确的。

否则(红色部分)我们就会发现,对于黑线右边的这一部分,它们的 \(endpos\) 的集合加上 \(n\),但是左边这一部分不是,这两部分已经不一样了。

所以我们要分裂,假设我们分裂出 \(cq\),那么使 \(cq\) 成为黑线右边这一部分,\(q\) 成为黑线左边的,根据定义,此时 \(fail_{cq}\) 为原来的 \(fail_q\),\(fail_q\) 改成 \(fail_{cq}\)(因为等价类的大小,越往上跳越多);\(fail_u=cq\),就是说 \(u\) 贡献的这个 \(endpos\) 不会给到 \(q\),这是正确的。对于 \(cq\) 的出边,和 \(q\) 是一模一样的。

对于 \(p\) 剩下的 \(fail\),如果有 \(fail_{p',r}=q\) 那么改成 \(fail_{p',r}=cq\)。

现在维护 \(endpos\),就是在我们建立的新的 \(u\) 那里打标记就行了。

现在升级成广义 SAM。

每次加入新的字符串,我们的 \(tail=root\)。这个时候注意:如果 \(ch_{tail,r}\) 已经存在,我们该分裂的分裂,反正不用在跳 \(fail\) 了。

很多细节,看代码。

时空复杂度 \(O(n)\)。

code

双倍空间捏!

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
template<int N,int M> struct suffixam{
	int ch[N<<1][M],link[N<<1],len[N<<1],tot;
	suffixam():tot(1){link[1]=0,len[1]=0;}
	int split(int r,int p,int q){
		if(len[q]==len[p]+1) return q;
		int u=++tot; len[u]=len[p]+1;
		memcpy(ch[u],ch[q],sizeof ch[0]);
		link[u]=link[q],link[q]=u;
		for(;p&&ch[p][r]==q;p=link[p]) ch[p][r]=u;
		return u;
	}
	int expand(int r,int p){
		if(ch[p][r]) return split(r,p,ch[p][r]);
		int u=++tot; len[u]=len[p]+1;
		for(;p;p=link[p]){
			if(ch[p][r]) return link[u]=split(r,p,ch[p][r]),u;
			else ch[p][r]=u;
		}
		return link[u]=1,u;
	}
};
int n,cnt[2000010];
LL ans;
char a[1000010];
suffixam<1000010,26> s;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",a+1);
		int m=strlen(a+1),last=1;
		for(int j=1;j<=m;j++) cnt[last=s.expand(a[j]-'a',last)]++;
	}
	for(int i=2;i<=s.tot;i++) ans+=s.len[i]-s.len[s.link[i]];
	printf("%lld\n",ans);
	return 0;
}

标签:exSAM,ch,后缀,字符串,tail,endpos,fail,cq,模板
From: https://www.cnblogs.com/caijianhong/p/16863464.html

相关文章

  • 【模板】二元一次不定方程 exgcd
    postedon2022-09-1715:59:26|under模板|sourcecodeLLmod(LLx,LLm){return(x%m+m)%m;}LLexgcd(LLa,LLb,LLc,LL&x,LL&y){ if(!b)returnx=c/a,y=0,a;......
  • 【模板】二维数点
    postedon2022-10-2313:50:24|under模板|sourceproblem给定一个二维平面,多次询问\(x\in[l_x,r_x],y\in[l_y,r_y]\)的点有多少个。solution1(静态+在线):可持久化......
  • 【模板】网络流
    postedon2022-08-1214:14:05|under模板|source感谢讲师LQS带来的网络流专题。本文非常不严谨,请不要把它当作入门博客。0xFF目录0x00网络流及求法0x01......
  • 【模板】多项式乘法 FFT
    postedon2022-08-0223:57:12|under模板|source涉世不深,不会卡常,恳求大佬指教typedefcomplex<double>comp;constdoublePI=acos(-1);template<intN>struct......
  • 【模板】对拍
    postedon2022-10-1813:30:17|under模板|sourceconstchar*name="bit";#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;type......
  • 【模板】动态树 Link-Cut Tree
    postedon2022-08-1718:05:59|under模板|sourcetemplate<intN>structlctree{ intval[N+10],sum[N+10],fa[N+10],ch[N+10][2],rev[N+10]; boolgetson(intp)......
  • 【模板】点分治 Centroid Decomposition
    postedon2022-07-2018:59:16|under模板|source0x00模板(P3806)给定\(n,k\)和一棵树,计算\[\sum\limits_{i,j\leqn}[{\ttdist}(i,j)=k]\]即树上距离为\(k\)......
  • 【模板】并查集 DSU
    postedon2021-09-1215:49:52|under模板|source0x00模板并查集维护的是这样一个问题:\(n\)个点,初始时每个点自己一个集合。\({\ttmerge}(x,y)\):合并\(x,y\)......
  • 【模板】Z 函数(扩展 KMP)
    postedon2022-08-0823:29:53|under模板|source#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;typedeflonglongLL;intn,......
  • 【模板】Tarjan
    postedon2022-07-0720:52:49|under模板|source0x00有向图缩点现有一有向图\(G=(V,E)\),称一个点集\(E'\inE\)为强连通分量,当且仅当\(E'\)的任意两点可以互......