SAM学习总结
学习blog: 史上最通俗的后缀自动机详解
(文章长度一个小时,上文作者学了两天,本蒟蒻学了三个星期 QwQ )
先定义:
在原串中除了位置不同,字符串本身完全相同的子串
本质相同的一类子串的右端点集合
性质:本质相同的一类子串对应一个右端点集合,一个右端点集合可能对应多类(本质互不相同的)本质相同的子串类
SAM的精髓,就在于先把所有本质相同的子串合并成若干子串类,再把endpos相同的子串类合并成若干个endpos类,合并了大量有效信息
SAM的每个结点对应一个endpos等价类,也就是一个子串集合
性质:对每个结点对应的子串集合本质相同的去重,剩下的子串在原串中是连续的一段
SAM的转移边标有字符,从一个节点指向另一个节点,表示该结点对应的去重
子串集合尾部加上该字符可以变成下一个endpos等价类
SAM每个结点有一条父向边,表示该类后缀中最长的,与该类endpos集合不等价
的子串所在的endpos集合
SAM每个结点有一个长度值,表示该endpos等价类中最长子串长度
构造代码:
struct SAM{
int ch[N][26],fa[N],len[N],tot,las;
int& operator [](const int& x){return len[x];}
void ins(int c){
int p=(las?las:n+1),np=++las;for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p){fa[np]=n+1;return;}int q=ch[p][c];
if(len[q]==len[p]+1){fa[np]=q;return;}int nq=++tot;
len[nq]=len[p]+1;fa[nq]=fa[q];For(i,0,25)ch[nq][i]=ch[q][i];
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;fa[q]=fa[np]=nq;
}
void build(){
scanf("%s",s+1);n=strlen(s+1);tot=n+1;las=0;
For(i,1,n)len[i]=i;For(i,1,n)ins(s[i]-'a');
}
};
//这样构造的话,SAM结点编号与前缀右端点位置就直接对应了

浙公网安备 33010602011771号