【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;
}
posted @ 2022-07-22 11:15  あおいSakura  阅读(29)  评论(0编辑  收藏  举报