SAM学习总结

学习blog: 史上最通俗的后缀自动机详解

(文章长度一个小时,上文作者学了两天,本蒟蒻学了三个星期 QwQ )

先定义:

  • 本质相同的子串:
    在原串中除了位置不同,字符串本身完全相同的子串
    
  • endpos
    本质相同的一类子串的右端点集合
    

    性质:本质相同的一类子串对应一个右端点集合,一个右端点集合可能对应多类(本质互不相同的)本质相同的子串类

    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结点编号与前缀右端点位置就直接对应了
    
  • posted @ 2021-07-11 10:56  Sherlockk  阅读(94)  评论(0)    收藏  举报