sam实质:将一个字符串高度压缩后的后缀放入一个自动机内,使得这个自动机可以接受所有文本的字串
endpos:字串末尾在原串中出现位置的集合
parent tree:若一个节点的endpos是另一个的子集,那么parent tree有一条由母集到子集的边
自动机中,每个状态代表的是endpos集合相等的一些字符串
添加字符是分三种情况
令未加入这个字符的为原串,las为原串所在节点
1.没有这个字符:las所在链上所有点向新节点连边
2.若有
2.1.若本来这个字符和原串的某个后缀一起出现在字符串的某个地方过,就让新节点向表示原串某后缀+新字符这个节点连边
2.2否则复制这个节点,将他看作是代表原串某后缀+新字符的一个节点,再进行一系列操作
void insert(char ch){
int now=++sz;
mes[now].len=mes[las].len+1;
while(las&&!mes[las].nxt[ch]) mes[las].nxt[ch]=now,las=mes[las].fa;//连转移
if(!las) mes[now].fa=1;//没有出现过这个字符
else{
int to=mes[las].nxt[ch];
if(mes[to].len==mes[las].len+1) mes[now].fa=to;//2.1种情况
else{//2.2种情况:复制节点
int np=++sz;
mes[np]=mes[to],mes[np].len=mes[las].len+1;
while(las&&mes[las].nxt[ch]==to) mes[las].nxt[ch]=np,las=mes[las].fa;
mes[to].fa=mes[now].fa=np;
}
}
las=now;
}