模板:广义SAM(字符串)
2022/1/22 23:08:56
本文主要是介绍模板:广义SAM(字符串),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
所谓广义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;
这篇关于模板:广义SAM(字符串)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-07转型传统行业避坑指南!
- 2025-01-07百万架构师第九课:源码分析:Spring 源码分析:Spring5源码分析-预习资料|JavaGuide
- 2025-01-07为你的程序精选的4个优质支付API
- 2025-01-06责任分配矩阵在项目管理中的作用:结合工具提升团队生产力
- 2025-01-06板栗看板:优化项目管理的实用策略,助你轻松完成任务
- 2025-01-06电商小白怎么选取合适的工具?一站式工具指南来啦
- 2025-01-06企业如何避免春节期间的项目断层?四大方法教给你!
- 2025-01-06初创团队如何在动态环境下利用看板工具快速迭代
- 2025-01-06企业内部管理如何实现高效?四大策略教会你
- 2025-01-06给 Postgres 写一个向量插件 - 向量类型