回文树
正着反着做一遍回文树即可。然而好久没写回文树了,调了好一会儿。大概把一些细节讲一下。
需要建两个根root1(len = -1)和root2(len = 0),其中root1的pre是自己,root2的pre是root1。
找一个新节点np的pre时,要从p->pre开始找。因此如果p = root1则np的pre只能是root1,否则可以递归查找。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define S 30
using namespace std;
namespace runzhe2000
{
char s[N];
int l[N], r[N], n;
struct PT
{
PT *pre, *ch[S];
int len;
}mem[N*5], *tot, *null, *root1, *root2;
PT *newPT(int v)
{
PT *p = ++tot;
p->pre = null;
for(int i = 0; i < S; i++) p->ch[i] = null;
p->len = v;
return p;
}
void init()
{
tot = mem;
null = ++tot;
null->pre = null;
for(int i = 0; i < S; i++) null->ch[i] = null;
null->len = 0;
root1 = newPT(-1);
root2 = newPT(0);
root2->pre = root1;
root1->pre = root1;
}
void PT_build(int *mx)
{
PT *p = root1;
for(int i = 1; i <= n; i++)
{
int v = s[i] - 'a';
while( i-p->len-1 >= 0 && s[i] != s[i-p->len-1]) p = p->pre;
if(p->ch[v] == null)
{
p->ch[v] = newPT(p->len + 2);
if(p->len == -1) p->ch[v]->pre = root2;
else
{
PT *q = p->pre;
for(; s[i] != s[i-q->len-1]; q = q->pre);
p->ch[v]->pre = q->ch[v];
}
}
p = p->ch[v];
mx[i] = p->len;
}
}
void main()
{
scanf("%s",s+1);
n = strlen(s+1);
s[0] = -1;
init();
PT_build(l);
for(int i = 1, ii = n/2; i <= ii; i++) swap(s[i], s[n-i+1]);
init();
PT_build(r);
int ans = 0;
l[0] = l[n+1] = r[0] = r[n+1] = -1;
for(int i = 0; i <= n; i++) ans = max(ans, l[i] + r[n-i]);
printf("%d\n",ans);
}
}
int main()
{
runzhe2000::main();
}