题意:给出一个串,求其中任意两个字串的lcp的总和。
我们可以对于这个串建一颗后缀自动机,实际上,他的parent边树就是一颗后缀树,我们在后缀树上统计答案,设f表示right集合的大小,可以理解为后缀树的siz,然后w是f的前缀和。mx按照基数排序,然后扫一遍就可以统计答案了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#include<map>
using namespace std;
int n,m;
typedef long long ll;
const int N=1e6+5;
map<int,int>ch[N];
int mx[N],fa[N],f[N],g[N],b[N],c[N];
int last,cnt;
char s[N];
ll ans;
inline void ins(int x)
{
int p,q,np,nq;//p:status 0;
p=last; //np:newnode
last=np=++cnt;
mx[np]=mx[p]+1;
g[np]=f[np]=1;
for(;!ch[p][x]&&p;p=fa[p])ch[p][x]=np;
if (!p)fa[np]=1;
else
{ //nq:son[q]
q=ch[p][x];//q:laststatus
if (mx[q]==mx[p]+1)fa[np]=q;
else
{
nq=++cnt;
mx[nq]=mx[p]+1;
ch[nq]=ch[q];
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
}
inline ll solve()
{
fo(i,1,cnt)b[mx[i]]++;
fo(i,1,n)b[i]+=b[i-1];
fo(i,1,cnt)c[b[mx[i]]--]=i;
fd(i,cnt,1)f[fa[c[i]]]+=f[c[i]];
ll ans=0;
fo(i,1,cnt)
{
ans+=1ll*g[fa[i]]*f[i]*mx[fa[i]];
g[fa[i]]+=f[i];
}
return ans;
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
last=cnt=1;
fo(i,1,n)ins(s[i]-'a');
ans=0;
fo(i,1,n)ans+=1ll*i*(n-1);
printf("%lld\n",ans-solve()*2);
return 0;
}