在线构造回文树
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitfile/sign/e66be3ca1b38d62dc9b42bc331efaa7b" alt="" /></p>
<hr />
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitfile/sign/6e8ee9df0b861027e0ceb84da3b267a2" alt="" /></p>
<hr />
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitfile/sign/bb8ab51361fe49649fcc44135e63973c" alt="" /></p>
<hr />
<pre><code class="language-cpp">namespace pam_tree{
int next[maxn][26], fail[maxn];//这个26是字符个数,按要求改
//next[i][c]表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号(和字典树类似)。
//fail[i]表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串(和AC自动机类似)。
int cnt[maxn], num[maxn], len[maxn];
//cnt[i]表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
//num[i]表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。
//len[i]表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串)
int S[maxn], last, n, p;
//S[i]表示第i次添加的字符(一开始设S[0] = -1(可以是任意一个在串S中不会出现的字符))。
//last指向新添加一个字母后所形成的最长回文串表示的节点。
//p表示添加的节点个数。
//n表示添加的字符个数。
int newnode(int l){
for(int i = 0; i < 26; ++i) next[p][i] = 0;
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 -= 'a';
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];
}
};</code></pre>