LibreOJ 6626.幼儿园唱歌题

当时这场比赛在某谷举办结束的时候我瞅了眼题解,然后记住了这道题要回文自动机(
学了之后来还愿(雾

看到区间的前缀 & 后缀,显然建正反串 PAM。
注意到不同回文自动机上不能方便地匹配。
但是由于回文串正反都一样,所以可以考虑建广义 PAM。

广义 PAM 是什么?比广义 SAM 简单多了(
仔细考察建 PAM 的过程,发现直接每次令 \({\rm las} = 1\) 就对了(

然后记录每个前 / 后缀插入得到的状态(即其最长回文后 / 前缀
倍增找到区间内最长回文前 / 后缀,然后在 Fail 树上求 LCA,LCA 的长度的相反数即是答案。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 4e5;
const int LG = 19;
int n,q;
char s[N + 5],t[N + 5];
int ed[N + 5],st[N + 5];
namespace PAM
{
struct node
{
int ch[26];
int fa,len;
} pam[N + 5];
int las = 1,tot = 1;
int f[LG + 5][N + 5],dep[N + 5];
inline int init()
{
pam[1].len = -1,pam[0].fa = 1;
return 0;
}
int Init = init();
inline void insert(char *s,int i)
{
int cur = las,x = s[i] - 'a';
for(;s[i - pam[cur].len - 1] ^ s[i];cur = pam[cur].fa);
if(!pam[cur].ch[x])
{
int p = ++tot,q = pam[cur].fa;
pam[p].len = pam[cur].len + 2;
for(;s[i - pam[q].len - 1] ^ s[i];q = pam[q].fa);
pam[p].fa = pam[q].ch[x],pam[cur].ch[x] = p;
}
las = pam[cur].ch[x];
}
inline void build()
{
for(register int i = 2;i <= tot;++i)
dep[i] = dep[f[0][i] = pam[i].fa] + 1;
for(register int i = 1;i <= LG;++i)
for(register int j = 2;j <= tot;++j)
f[i][j] = f[i - 1][f[i - 1][j]];
}
inline int get(int p,int x)
{
if(pam[p].len <= x)
return p;
for(register int i = LG;~i;--i)
if(pam[f[i][p]].len > x)
p = f[i][p];
return f[0][p];
}
inline int getlca(int x,int y)
{
dep[x] < dep[y] && (swap(x,y),1);
for(register int i = LG;~i;--i)
if(dep[f[i][x]] >= dep[y])
x = f[i][x];
if(x == y)
return x;
for(register int i = LG;~i;--i)
if(f[i][x] ^ f[i][y])
x = f[i][x],y = f[i][y];
return f[0][x];
}
}
int main()
{
scanf("%d%d%s",&n,&q,s + 1);
for(register int i = 1;i <= n;++i)
PAM::insert(s,i),ed[i] = PAM::las,t[n - i + 1] = s[i];
PAM::las = 1;
for(register int i = 1;i <= n;++i)
PAM::insert(t,i),st[n - i + 1] = PAM::las;
PAM::build();
for(int l1,r1,l2,r2;q;--q)
scanf("%d%d%d%d",&l1,&r1,&l2,&r2),
printf("%d\n",-PAM::pam[PAM::getlca(PAM::get(st[l1],r1 - l1 + 1),PAM::get(ed[r2],r2 - l2 + 1))].len);
}