【字符串】回文树学习笔记

燃鹅,一年后的我在想,回文树是个什么东西?(._."||)

 2020-10-08


好好理解了回文树。

理解后的感觉:为啥子之前会觉得很复杂?Orz

根据自己理解改了个自己能看懂的模板

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;

int last,tot,n;
int nex[maxn][27],len[maxn],fail[maxn],s[maxn],cnt[maxn];
/*
n 是字符串的长度
last 是当前节点的上一节点 记录信息的节点编号从1开始
next[i][j] 是 i节点左右添加字符x后所形成的新的字符串的 节点标号
len[i] 是i节点所代表的字符串的长度
fail[i] 是节点i的最长回文后缀的 节点标号
s[i] 是字符串的第i个字符
cnt[i] 是i节点所代表的的回文串在整个字符串里出现的次数
*/
inline void init()
{
    s[0]=-1;fail[0]=1;last=0;
    len[0]=0;len[1]=-1;tot=1;
}
/*
零号节点的最长回文后缀是指向1号节点 而1号节点的长度是 len[1]=-1;
这个操作有利于:
当添加第一个字符时(节点2) 新的回文串长度 恰好等于:-1+2=1
*/
inline int getfail(int x,int id)
{
    while(s[id-len[x]-1]!=s[id])x=fail[x];
    return x;
}
/*
从x节点往下找 找回文后缀恰好回文后缀的前一个字符等于要添加的字符
使得能构成一个新的回文后缀
若找不到,则结果是回到1号节点 然后再添加新字符 则形成了一个长度为1的回文串
len[1]=-1有利于
在找不到的情况下 最后一定能找到1号节点满足:
(s[id-len[1]-1]=s[id-(-1)-1])==s[id]
*/
inline int newnode(int x)
{
    len[++tot]=x;
    return tot;
}
inline int solve()
{
    int i,p,q=1;
    init();
    for(i=1;i<=n;i++)
    {
        p=getfail(last,i);
        //找到上一节点可以添加s[i]字符的回文后缀所在的节点标号 p
        if(nex[p][s[i]]==0)//如果 p节点没有过两边添加s[i]的记录
        {
            printf("%d %d ",i,q);
            q=newnode(len[p]+2);//新字符串为p串两边添加s[i]
            fail[q]=nex[getfail(fail[p],i)][s[i]];
            //q的最长回文后缀是 p的满足前一个字符是s[i]的回文后缀再加字符s[i]的回文串所在节点 没有则为节点0
            nex[p][s[i]]=q;

            for(int j=i-len[q]+1;j<=i;j++)printf("%c",s[j]+'a');
            putchar(10);
        }
        last=nex[p][s[i]];//将当前节点更新到上一节点
        cnt[nex[p][s[i]]]++;//这个回文串出现的记录+1
    }
    for(i=tot;i>1;i--)
    {
        cnt[fail[i]]+=cnt[i];
        /*
        i节点出现必是包含其回文后缀的出现
        所以最后需要更新回文后缀出现的次数
        因为之前更新的节点所代表的串 都不会是别的串的最长回文后缀
        */
    }
}
int main()
{
    char s1[maxn];
    scanf("%s",s1);
    n=strlen(s1);
    for(int i=1;i<=n;i++)s[i]=s1[i-1]-'a';
    solve();
}

2019-09-10 22:39:54


P3649

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+50;

char ss[maxn];
int last,tot,n;
int nex[maxn][27],len[maxn],fail[maxn],s[maxn],cnt[maxn];
inline void init()
{
    n=strlen(ss);
    for(int i=1;i<=n;i++)s[i]=ss[i-1]-'a';
    s[0]=-1;fail[0]=1;last=0;
    len[0]=0;len[1]=-1;tot=1;
}
inline int getfail(int x,int id)
{
    while(s[id-len[x]-1]!=s[id])x=fail[x];
    return x;
}
inline int newnode(int x)
{
    len[++tot]=x;
    return tot;
}
inline void PT()
{
    int p,q=1;
    init();
    for(int i=1;i<=n;i++)
    {
        p=getfail(last,i);
        if(nex[p][s[i]]==0)
        {
//            printf("%d %d ",i,q);
            q=newnode(len[p]+2);
            fail[q]=nex[getfail(fail[p],i)][s[i]];
            nex[p][s[i]]=q;
//            for(int j=i-len[q]+1;j<=i;j++)printf("%c",s[j]+'a');putchar(10);
        }
        last=nex[p][s[i]];
        cnt[nex[p][s[i]]]++;
    }
    for(int i=tot;i>1;i--)cnt[fail[i]]+=cnt[i];
}
inline int solve()
{
    ll ans=0;
    PT();
    for(int i=1;i<=tot;i++)ans=max(ans,(ll)len[i]*cnt[i]);
    printf("%lld
",ans);
}
int main()
{
    scanf("%s",ss);
    solve();
}
原文地址:https://www.cnblogs.com/kkkek/p/11503579.html