标准版
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int N=26;
struct Palindromic_Tree
{
int next[maxn][N];
int fail[maxn];
int cnt[maxn];//第i个节点表示的回文串出现的次数,最后要调用count函数完成计算
int num[maxn];//以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
int len[maxn];//节点i表示的回文串的长度
int S[maxn];//存放添加的字符
int last;
int n;//字符数组指针
int p;//节点指针
int newnode(int l)
{
memset(next[p],0,sizeof next[p]);
cnt[p]=0;
num[p]=0;
len[p]=l;
return p++;
}
void init()
{
p=0;
newnode(0);
newnode(-1);
last=0;
n=0;
S[n]=-1;
fail[0]=1;
}
int get_fail(int x)
{
while(S[n-len[x]-1]!=S[n])
x=fail[x];
return x;
}
void add(int c)
{
c-='0';
S[++n]=c;
int cur=get_fail(last);
if(!next[cur][c])//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
{
int now=newnode(len[cur]+2);
fail[now]=next[get_fail(fail[cur])][c];
next[cur][c]=now;
num[now]=num[fail[now]]+1;
}
last=next[cur][c];
cnt[last]++;
}
void count()
{
for(int i=p-1;i>=0;i--)
cnt[fail[i]]+=cnt[i];
}
}pam;
char s[maxn];
int main()
{
pam.init();
scanf("%s",s);
int n=strlen(s);
for(int i=0;i<n;i++)
{
pam.add(s[i]);
}
}
双向插入版
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int N=26;
struct Palindromic_Tree {
static const int maxn=400000;
static const int Letter=26;
deque<int> text;
int len[maxn];//len[i]表示节点i表示的回文串的长度
int cnt[maxn];//第 i 节点表示的回文串出现的次数、注意最后调用 getCnt 函数完成计算
int num[maxn];//表示以节点 i 代表的回文串端点为端点的不同回文串个数
int next[maxn][Letter];//next静态指针和字典树类似,指向的串为当前串两端加上同一个字符构成
int fail[maxn];//失配指针
int odd, even;//奇偶原始节点
int pre, suf;
int totNode;//自动机所有节点的个数
LL totNum;//串中所有回文串数量
int newNode(int _len)
{
int ret=totNode++;
len[ret]=_len;
cnt[ret]=num[ret]=0;
fail[ret]=0;
memset(next[ret],0,sizeof(next[ret]));
return ret;
}
inline void init()
{
text.clear();
totNode=0;
totNum=0;
even=newNode(0);
odd=newNode(-1);
fail[even]=fail[odd]=odd;
pre=suf=even;
}
int encode(char c)
{
return c - 'a';
}
template<typename FunT>
int getFail(int ch,int cur,FunT getNext)
{
for(int i=getNext(len[cur]);
i<0||i>=(int)text.size()||text[i]!=ch;
cur=fail[cur],i=getNext(len[cur]));
return cur;
}
template<typename FunT>
int Insert(int ch,int last,FunT getNext)
{
last=getFail(ch,last,getNext);
if(!next[last][ch])
{
int cur=newNode(len[last]+2);
fail[cur]=next[getFail(ch,fail[last],getNext)][ch];
next[last][ch]=cur;
num[cur]=num[fail[cur]]+1;
}
last=next[last][ch];
totNum+=(LL)num[last];
cnt[last]++;
return last;
}
int push_front(char c)
{
text.push_front(encode(c));
pre=Insert(encode(c),pre,[](int i)->int{ return i+1;});
if(len[pre]==(int)text.size()) suf=pre;
return totNode;
}
int push_back(char c)
{
text.push_back(encode(c));
suf=Insert(encode(c),suf,[this](int i)->int{ return this->text.size()-i-2; });
if(len[suf]==(int)text.size()) pre=suf;
return totNode;
}
int push_front(char *s)
{
int ret=0;
for(int i=0;s[i];i++)
ret=push_front(s[i]);
return ret;
}
int push_back(char *s)
{
int ret=0;
for(int i=0;s[i];i++)
ret=push_back(s[i]);
return ret;
}
inline void getCnt()
{
for(int i=totNode-1;i>=0;i--)
cnt[fail[i]]+=cnt[i];
}
}pam;