1833. 后缀数组

一种参考实现:

#include <bits/stdc++.h> using namespace std; using ll = long long; const ll mn = 1e6 + 10; struct suffixArray { ll n, m; // m是字符集(char)大小 ll sa[mn], rk[mn * 2], hei[mn], ct[mn], s2[mn], r1[mn]; char *s; void calcSA() { for (ll i = 0; i <= m; ++i) { ct[i] = 0; } for (ll i = n + 1; i <= n * 2; ++i) { rk[i] = 0; } for (ll i = 1; i <= n; ++i) { rk[i] = s[i]; ct[rk[i]]++; } for (ll i = 1; i <= m; ++i) { ct[i] += ct[i - 1]; } for (ll i = n; i >= 1; --i) { sa[ct[rk[i]]--] = i; } ll mx = m; for (ll j = 1, k = 0; k < n; j *= 2, mx = k) { ll p = 0; for (ll i = n - j + 1; i <= n; ++i) { s2[++p] = i; } for (ll i = 1; i <= n; ++i) { if (sa[i] > j) { s2[++p] = sa[i] - j; } } for (ll i = 0; i <= mx; ++i) { ct[i] = 0; } for (ll i = 1; i <= n; ++i) { ct[rk[s2[i]]]++; } for (ll i = 1; i <= mx; ++i) { ct[i] += ct[i - 1]; } for (ll i = n; i >= 1; --i) { sa[ct[rk[s2[i]]]--] = s2[i]; } r1[sa[1]] = k = 1; for (ll i = 2; i <= n; ++i) { if (rk[sa[i - 1]] == rk[sa[i]] && rk[sa[i - 1] + j] == rk[sa[i] + j]) { r1[sa[i]] = k; } else { r1[sa[i]] = ++k; } } for (ll i = 1; i <= n; ++i) { rk[i] = r1[i]; } } } void calcHeight() { hei[1] = 0; for (ll i = 1, j; i <= n; ++i) { if (rk[i] == 1) { continue; } j = max(hei[rk[i - 1]] - 1, 0LL); while (s[i + j] == s[sa[rk[i] - 1] + j]) { ++j; } hei[rk[i]] = j; } } ll t1[mn][20], lg2[mn]; void initLCP() { for (ll i = 2; i <= n; ++i) { lg2[i] = lg2[i / 2] + 1; } for (ll i = 1; i <= n; ++i) { t1[i][0] = hei[i]; } for (ll j = 1; j <= 20; ++j) { for (ll i = 1; i + (1 << j) - 1 <= n; ++i) { t1[i][j] = min(t1[i][j - 1], t1[i + (1 << (j - 1))][j - 1]); } } } void build(char *t) { s = t, n = strlen(s + 1), m = 'z'; calcSA(); calcHeight(); initLCP(); } ll lcp(ll x, ll y) { ll l = rk[x], r = rk[y]; if (l > r) { swap(l, r); } ++l; ll k = lg2[r - l + 1]; // or __lg(r-l+1); return min(t1[l][k], t1[r - (1 << k) + 1][k]); } } s1, s2; char s[mn]; ll n, t, l, r; signed main() { cin.tie(0)->ios::sync_with_stdio(false); cin >> s + 1; n = strlen(s + 1); s1.build(s); reverse(s + 1, s + 1 + n); s2.build(s); for (cin >> t; t; --t) { cin >> l >> r; cout << s1.lcp(l, r) << ' ' << s2.lcp(n - l + 1, n - r + 1) << '\n'; } return 0; }