​LINK​

学了 A C M A ACMA ACMA学这个感觉好简单…就是个 a c ac ac自动机吧这…

回文树有两棵树,一个树上都是奇数回文,一颗树上都是偶数回文

节点 x x x代表的回文串是 x x x走向根节点,再由根节点走向 x x x的路径字母

当然,奇数回文树和根节点相连的边只走一次,那个是对称中心

考虑增量构造法,设 [ 1 , i − 1 ] [1,i-1] [1,i−1]匹配节点在 l a s las las位置

那么我们需要找到树上能接上 s [ i ] s[i] s[i]的最长回文子串,那么可以一直跳 f a i l fail fail找

然后处理自己的 f a i l fail fail,就是再往上跳 f a i l fail fail找到符合条件的节点

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
char s[maxn];
struct PAM
{
int zi[maxn][26],fail[maxn],len[maxn],las,id,cnt[maxn];
PAM()
{
len[0] = 0, len[1] = -1;
fail[0] = 1, fail[1] = 1; las = id = 1;
}
int get_fail(int u,int index)
{
while( s[index-len[u]-1]!=s[index] ) u = fail[u];
return u;
}
void insert(int x,int index)
{
int u = get_fail(las,index);
if( !zi[u][x] )//没有这个节点
{
int newnode = ++id, v = get_fail(fail[u],index);
len[newnode] = len[u]+2;
fail[newnode] = zi[v][x]; zi[u][x] = newnode;
cnt[newnode] = cnt[fail[newnode]]+1;
}
las = zi[u][x];
}
void solve(char s[])
{
int len = strlen( s+1 );
for(int i=1;i<=len;i++)
{
insert( s[i]-'a'+1,i );
s[i+1] = ( s[i+1]-97+cnt[las] ) % 26 + 97;
printf("%d ",cnt[las] );
}
}
}T;
int main()
{
scanf("%s",s+1 );
T.solve(s);
}