征集后缀自动机解法。
后缀数组写法:
#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;
}
}
void build(char *t)
{
s = t, n = strlen(s + 1), m = 'z';
calcSA();
calcHeight();
}
} s1;
char s[mn];
ll n, t;
signed main()
{
cin.tie(0)->ios::sync_with_stdio(false);
cin >> t;
while (t--)
{
cin >> s + 1;
n = strlen(s + 1);
s1.build(s);
ll ans = n * (n + 1) / 2;
for (ll i = 2; i <= n; ++i)
ans -= s1.hei[i];
cout << ans << '\n';
}
return 0;
}