标签:技术 src end 图片 empty size aaa pre continue
后缀自动机可以理解为是将字符串所有后缀所建出的\(Trie\)进行压缩后得出的\(DAG\)
对于一个子串\(s\),它结束位置的集合称为\(endpos(s)\),如对于\(aaabbaab\),\(endpos(ab)={4,8},endpos(bb)={5}\)
\(s_1,s_2\)为原串的两个子串,设\(|s_1| \leqslant |s_2|\),则\(s_1\)是\(s_2\)的后缀当且仅当\(endpos(s_2) \subseteq endpos(s_1)\),\(s_1\)不是\(s_2\)的后缀当且仅当\(endpos(s_1) \cap endpos(s_2)= \varnothing\)
如果两个子串的\(endpos\)相同,则其中子串一个为另一个的后缀
由\(endpos\)的包含关系可以得出一个树形结构,称为\(Parent\)树
后缀自动机的节点就是\(Parent\)树的节点,每个节点表示一个\(endpos\)
\(SAM\)的节点数不超过\(2n-1\),边数不超过\(3n-4\),数组大小应开成两倍
\(len:\)为一个\(endpos\)所对应的子串中最长子串的长度
\(ch:\)为转移函数
\(fa:\)为后缀连接
设\(minlen\)为一个\(endpos\)所对应的子串中最短子串的长度,得
\(len[fa[i]]+1=minlen[i]\)
后缀自动机是一张有向无环图,其中顶点是状态,而边代表了状态之间的转移
每一个状态包含了它包含的最长子串的一些连续长度的后缀,不是所有后缀,再短的其他后缀在\(fa\)连接的状态,也就是该串的所有后缀在\(Parent\)树的链上
从初始状态经由任意路径走到某一终止状态,得到的字符串为原串的某一后缀
从初始状态经由任意路径走到某一状态,得到的字符串为原串的某一子串
所有终止状态包含了原串的所有后缀,所有终止状态又用\(fa\)相连
如\(abbb\)
构造\(SAM\)时有三种情况
① \(\ aa\ \to \ aab\)
② \(\ aabb\ \to \ aabba\)
③ \(\ aab\ \to \ aabb\)
\(code:\)
void init()
{
las=tot=1;
}
void insert(int c)
{
int p=las,np=las=++tot;
len[np]=len[p]+1;
while(p&&!ch[p][c]) ch[p][c]=np,p=fa[p];
if(!p)
{
fa[np]=1;
return;
}
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tot;
len[nq]=len[p]+1;
fa[nq]=fa[q],fa[np]=fa[q]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
while(ch[p][c]==q) ch[p][c]=nq,p=fa[p];
}
}
一个状态包含的子串的出现次数可以先拓扑,再用\(fa\)求出,\(siz\)初值为\(1\),\(siz[1]\)应为\(0\)
\(code:\)
void calc()
{
for(int i=1;i<=tot;++i) b[len[i]]++;
for(int i=1;i<=tot;++i) b[i]+=b[i-1];
for(int i=1;i<=tot;++i) ord[b[len[i]]--]=i;
for(int i=tot;i;--i)
{
int p=ord[i];
siz[fa[p]]+=siz[p];
}
}
广义后缀自动机,在\(trie\)上建\(SAM\)
\(code:\)
void init()
{
las=tot=pre[0]=1;
}
void insert(int c)
{
int p=las,np=0;
if(!ch[p][c])
{
np=las=++tot;
len[np]=len[p]+1;
}
while(p&&!ch[p][c]) ch[p][c]=np,p=fa[p];
if(!p)
{
fa[np]=1;
return;
}
int q=ch[p][c];
if(len[q]==len[p]+1)
{
if(np) fa[np]=q;
else las=q;
}
else
{
int nq=++tot;
if(!np) las=nq;
len[nq]=len[p]+1;
fa[nq]=fa[q],fa[q]=nq;
if(np) fa[np]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
while(p&&ch[p][c]==q) ch[p][c]=nq,p=fa[p];
}
}
void bfs(int s)
{
queue<int> q;
q.push(s);
fath[s]=0;
while(!q.empty())
{
int x=q.front();
q.pop();
las=pre[fath[x]];
insert(co[x]);
pre[x]=las;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fath[x]) continue;
fath[y]=x;
q.push(y);
}
}
}
......
for(int i=1;i<=n;++i)
if(d[i]==1)
bfs(i);
标签:技术 src end 图片 empty size aaa pre continue
原文地址:https://www.cnblogs.com/lhm-/p/12229578.html