求公共 (border),,,求 (border) 我会,(KMP)。那么我直接做 M 次 KMP。
显然会TLE,但是我们也可以用 (KMP) 先求一下原串的 (border)。
然后我们可以发现,(border) 的 (border) 也是 (border) 那么我们可以利用这个关系建一棵树,然后我们可以发现,对于这样一棵树,最近公共祖先就是公共 (border) 的长度。那么我们倍增跳就行了。
(注意:当 (p, q) 是 (lca) 的时候,要再向上跳一层,因为 (border) 要求左闭右开)
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll MAXN = 1e6+10;
ll N, M, fa[MAXN][22], dep[MAXN];
char ss[MAXN];
void gtn();
ll lca(ll, ll);
int main() {
ios::sync_with_stdio(false);
cin >> (ss+1);
gtn();
cin >> M;
for (ll i = 1, p, q; i <= M; i++) {
cin >> p >> q;
ll lc = lca(p, q);
if (lc == p || lc == q) lc = fa[lc][0];
printf("%lld
", lc);
}
return 0;
}
ll lca(ll x, ll y) {
if (dep[x] < dep[y]) swap(x, y);
ll dis = dep[x] - dep[y];
for (ll i = 20; ~i; i--) {
if ((dis >> i) & 1) {
x = fa[x][i];
}
}
if (x == y) return x;
for (ll i = 20; ~i; i--) {
if (fa[x][i] != fa[y][i]) {
x = fa[x][i];
y = fa[y][i];
}
}
return fa[x][0];
}
void gtn() {
ll len = strlen(ss+1);
for (ll i = 2, j = 0; i <= len; i++) {
while (j != 0 && ss[j+1] != ss[i]) j = fa[j][0];
if (ss[j+1] == ss[i]) j++;
fa[i][0] = j, dep[i] = dep[j]+1;
}
for (ll i = 1; i <= 20; i++) {
for (ll j = 1; j <= len; j++) {
fa[j][i] = fa[fa[j][i-1]][i-1];
}
}
}