回文树
tags:字符串
学习博客:https://blog.csdn.net/dacc123/article/details/51556837
一、概述
struct PAM
{
int fail[N],ch[N][26],len[N],nod,lst;
void init() {fail[0]=fail[1]=nod=1;len[1]=-1;}
void extend(int c,int i,char *s)
{
int p=lst;
while(s[i-len[p]-1]!=s[i]) p=fail[p];
if(ch[p][c]) {lst=ch[p][c];return;}
int x=++nod,k=fail[p];
while(s[i-len[k]-1]!=s[i]) k=fail[k];
fail[x]=ch[k][c];len[x]=len[p]+2;
lst=ch[p][c]=x;
}
};
回文树中每个节点表示以它结尾的最长回文后缀
其中0号点表示长度为0,1号点表示长度为-1,分别匹配偶回文和奇回文
(len)表示该回文后缀的长度,(fa)表示其(fail)——这个回文后缀的最长回文后缀
复杂度(O(n))
二、作用&性质
- 1.本质不同的回文串种数以及个数
回文串种数即nod的大小
每次extend后最后所在的点加1,则其fail链上的点都加1,即可算出某串的个数
- 2.以某点结尾的回文串个数(把串反过来就是以其开头的)
就是该位置所代表的点的fail链深度
- 3.前后加字符,动态构串
void extend(int c,int i,int &lst,int op)
{
int p=lst;
while(s[i-op*len[p]-op]!=s[i]) p=fail[p];
if(!ch[p][c])
{
int x=++nod,k=fail[p];
while(s[i-op*len[k]-op]!=s[i]) k=fail[k];
len[x]=len[p]+2;
fail[x]=ch[k][c];
dep[x]=dep[fail[x]]+1;
ch[p][c]=x;
}
lst=ch[p][c];ans+=dep[lst];
if(len[lst]==r-l+1) pre=suf=lst;
}
- 4.fail链上最长回文后缀长度等差
void extend(int c,int i)
{
int p=lst;
while(s[i]!=s[i-len[p]-1]) p=fail[p];
if(!ch[p][c])
{
int x=++nod,k=fail[p];
while(s[i]!=s[i-len[k]-1]) k=fail[k];
len[x]=len[p]+2;
fail[x]=ch[k][c];
ch[p][c]=x;
diff[x]=len[x]-len[fail[x]];
anc[x]=(diff[x]==diff[fail[x]])?anc[fail[x]]:fail[x];
}
lst=ch[p][c];
}
例题:https://www.cnblogs.com/cjyyb/p/8462865.html
三、完成了一些题目
- [HDU5421]Victor and String
- [Codeforces17E]Palisection
- [国家集训队]最长双回文串
- yyb 12.21 T2