洛谷P5829【模板】失配树(Border/KMP)

题目描述

给定一个字符串 ss,定义它的 k*k* 前缀 prekpre**k 为字符串 s1…ks1…kk*k* 后缀 sufksuf**k 为字符串 s∣s∣−k+1…∣s∣ss∣−k+1…∣s∣,其中 1≤k≤∣s∣1≤k≤∣s∣。

定义 Border(s)Borde****r(s) 为对于 i∈[1,∣s∣)*i*∈[1,∣*s*∣),满足 prei=sufi*p*r*e*i*=*s*u*f*i* 的字符串 preipre**i 的集合。Border(s)Borde****r(s) 中的每个元素都称之为字符串 ss 的 border⁡border。

有 mm 组询问,每组询问给定 p,qp,q,求 ssp*p* 前缀q*q* 前缀最长公共 border⁡border 的长度。

输入格式

第一行一个字符串 ss

第二行一个整数 mm

接下来 mm 行,每行两个整数 p,qp,q

输出格式

对于每组询问,一行一个整数,表示答案。若不存在公共 border⁡border,请输出 00。

输入输出样例

输入 #1复制

aaaabbabbaa
5
2 4
7 10
3 4
1 2
4 11

输出 #1复制

1
1
2
0
2

输入 #2复制

zzaaccaazzccaacczz
3
2 18
10 18
3 5

输出 #2复制

1
2
0

看到border的定义很难不想到kmp,对于一个串,其border的border就是这个串的border。因此可以建出next树,即跑一遍kmp求出next数组然后在next[i] = j的情况下从j到i连一条边。最后对于每个询问求出p和q的LCA即可。

#include <bits/stdc++.h>
#define N 1000005
#define next nxt
using namespace std;
string s;
int m, n;
int f[N][25], dep[N], next[N];
void get_nxt() {
	next[1] = 0;
	for(int i = 2, j = 0; i <= n; i++) {
		while(j > 0 && s[i] != s[j + 1]) j = next[j];
		if(s[i] == s[j + 1]) j++;
		next[i] = j;
		f[i][0] = j;
		dep[i] = dep[j] + 1;
	}
}
int lca(int p, int q) {
	if(dep[p] < dep[q]) swap(p, q);
	for(int i = 21; i >= 0; i--) if(dep[f[p][i]] >= dep[q]) p = f[p][i];
	for(int i = 21; i >= 0; i--) if(f[p][i] != f[q][i]) p = f[p][i], q = f[q][i];
	return f[p][0];//!
}
int main() {
	dep[0] = 0, dep[1] = 1;
	cin >> s;
	n = s.size();
	s = ' ' + s;
	get_nxt();
	for(int i = 1; i <= 21; i++) {
		for(int j = 1; j <= n; j++) {
			f[j][i] = f[f[j][i - 1]][i - 1];
		}
	}
	cin >> m;
	for(int i = 1; i <= m; i++) {
		int p, q;
		cin >> p >> q;
		cout << lca(p, q) << endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lipoicyclic/p/15170237.html