ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模板:广义SAM(字符串)

2022-01-22 22:30:21  阅读:128  来源: 互联网

标签:cur SAM int tr len fa 字符串 模板


所谓广义SAM,就是更广泛意义下的SAM

(逃)

前言

感觉字符串的理解难度的巅峰还是在SAM,广义SAM只是在套一些特判罢了,并不是太难理解。
可以解决多字符串的子串问题,几乎就是把SAM能做的东西从单串变成了多串。

解析

在线做法

有一个很流行的盗版做法是每次加入新串时把 l s t lst lst 重新赋值为 1 1 1,然后就和正常SAM一样做。
但这会出现一些问题,就是当 t r a n s l s t , c trans_{lst,c} translst,c​ 存在时,我们会加入空节点
这里的空节点的具体含义是指其 m i n l e n > m a x l e n minlen>maxlen minlen>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;

然而,这个做法对一棵 t r i e trie trie 树建SAM的时候复杂度是 O ( G ( T ) ) O(G(T)) O(G(T)) 的( G ( T ) G(T) G(T) 表示所有叶子的深度和),这在许多时候会被卡成 O ( n 2 ) O(n^2) O(n2),因此,我们需要寻找另一种做法。

离线做法

这个方法对于 t r i e trie trie 树建SAM的复杂度是优秀的 O ( T ) O(T) O(T)。
考虑bfs,从而使得深度单调不降。
每次取出队首,以它父亲在SAM上对应的结点 作为 l s t lst lst 进行插入即可。由于 t r i e trie trie 树本身的性质,此时必然有 t r a n s l s t , c = N U L L trans_{lst,c}=NULL translst,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;

标签:cur,SAM,int,tr,len,fa,字符串,模板
来源: https://blog.csdn.net/BUG_Creater_jie/article/details/122644847

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有