【luogu P5829】【模板】失配树(字符串)(KMP)
【模板】失配树
题目链接:luogu P5829
题目大意
给你一个字符串,多次询问问你两个前缀的最长公共 border 的长度。
一个 border 就是一个子串既是前缀又是后缀。
思路
考虑到 border 就是 fail 树上的一条链。
那公共的就是 LCA!
弄出来即可。
然后要注意的是 border 不能是自己,所以要特判一下如果是两个中的一个要跳到父亲那里。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e6 + 100;
char s[N];
int n, m, fa[N][21], deg[N];
int LCA(int x, int y) {
if (deg[x] < deg[y]) swap(x, y);
for (int i = 20; i >= 0; i--)
if (deg[fa[x][i]] >= deg[y]) x = fa[x][i];
if (x == y) return x;
for (int i = 20; i >= 0; i--)
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int main() {
scanf("%s", s + 1); n = strlen(s + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j && s[i] != s[j + 1]) j = fa[j][0];
if (s[i] == s[j + 1]) j++;
fa[i][0] = j; for (int k = 1; k <= 20; k++) fa[i][k] = fa[fa[i][k - 1]][k - 1]; deg[i] = deg[fa[i][0]] + 1;
}
scanf("%d", &m);
while (m--) {
int x, y;
scanf("%d %d", &x, &y);
int ans = LCA(x, y);
if (ans == x || ans == y) ans = fa[ans][0];
printf("%d\n", ans);
}
return 0;
}