A run is a maximal substring with smallest period and . Runs theorem (Bannai et al. 2015): fewer than runs, and the sum of exponents is below . Every square (tandem repeat) lies in a unique run whose period divides , so squares, cubes, “is there a repetition of exponent ”, counting square occurrences and distinct squares reduce to the runs. Main–Lorentz divide and conquer finds all runs in ( in about 0.2 s); the linear algorithm uses Lyndon roots and LCE queries (Lyndon Words).

TaskFrom the runs
all runs / maximal repetitionsruns(s)
occurrences of squares
repetition of exponent existssome run has
cubes, -th powersruns with /
primitively rooted squares, distinct squaresLyndon roots of the runs (at most distinct squares)
template <class T> vector<int> zFunctionT(const T& s) {
    int n = sz(s); vector<int> z(n); if (n > 0) z[0] = n;
    for (int i = 1, l = 0, r = 0; i < n; i++) { if (i < r) z[i] = min(r - i, z[i - l]); while (i + z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++; if (i + z[i] > r) l = i, r = i + z[i]; }
    return z;
}
template <class T> vector<int> zMatch(const T& text, const T& pat) {   // e[i] = LCP(text[i..], pat)
    int n = sz(text), m = sz(pat); vector<int> z = zFunctionT(pat), e(n);
    for (int i = 0, l = 0, r = 0; i < n; i++) {
        int k = i < r ? min(r - i, z[i - l]) : 0;
        while (i + k < n && k < m && text[i + k] == pat[k]) k++;
        e[i] = k; if (i + k > r) l = i, r = i + k;
    }
    return e;
}
template <class T> vector<array<int, 3>> runs(const T& s) { // {t, l, r}: all runs, sorted
    int n = sz(s); vector<array<int, 3>> found;             // {l, r, p}: maximal p-periodic intervals with r - l >= 2p
    auto add = [&](int l, int r, int p) { if ((l == 0 || s[l - 1] != s[l - 1 + p]) && (r == n || s[r] != s[r - p])) found.push_back({l, r, p}); };
    auto crossing = [&](int lo, int mid, int hi) {           // p-periodic intervals containing s[mid - 1, mid + 1)
        T u(s.begin() + lo, s.begin() + mid), v(s.begin() + mid, s.begin() + hi), w(s.begin() + lo, s.begin() + hi), ru(u.rbegin(), u.rend()), rw(w.rbegin(), w.rend());
        int nu = sz(u), nv = sz(v);
        vector<int> zu = zFunctionT(ru), zv = zFunctionT(v), right = zMatch(w, v), left = zMatch(rw, ru);
        for (int p = 1; p <= nu; p++) {                      // contains s[mid - p, mid]
            int a = p < nu ? zu[p] : 0, b = right[nu - p];
            if (b > 0 && a + b >= p) add(mid - p - a, mid + b, p);
        }
        for (int p = 1; p <= nv; p++) {                      // contains s[mid - 1, mid + p)
            int c = p < nv ? zv[p] : 0, d = left[nv - p];
            if (d > 0 && c + d >= p) add(mid - d, mid + p + c, p);
        }
    };
    auto rec = [&](auto&& self, int lo, int hi) -> void { if (hi - lo < 2) return; int mid = (lo + hi) / 2; self(self, lo, mid); self(self, mid, hi); crossing(lo, mid, hi); };
    rec(rec, 0, n);
    sort(all(found)); vector<array<int, 3>> res;
    for (int i = 0; i < sz(found); i++) { auto [l, r, p] = found[i]; if (!(i > 0 && found[i - 1][0] == l && found[i - 1][1] == r)) res.push_back({p, l, r}); }   // keep the smallest period
    sort(all(res)); return res;
}
template <class T> ll countSquareOccurrences(const T& s) {
    ll total = 0;
    for (auto [t, l, r] : runs(s)) { int L = r - l; for (ll k = t; 2 * k <= L; k += t) total += L - 2 * k + 1; }
    return total;
}