啊我又在写SAM……
反正题里求的就是反串后缀树上的各关键点之间的路径长度和
于是……dp一下
像我比较菜……
在本题rank1的lxl大爷的指导下
……嗯每条边出现的次数就是子树里关键点个数siz[i]*(n-siz[i])……显然…………嗨呀我好菜啊QAQ这都看不出来QAQ看来是要退役了
啊……反正这样写常数还是……不大的吧?
#include<bits/stdc++.h>
//#define Flaze_naive
#define MAXN 500005
using namespace std; char read_s[MAXN];
struct sam{
int son[MAXN<<1][26],pre[MAXN<<1],dis[MAXN<<1];
int Right[MAXN<<1];
int p,np,q,nq,lst,cnt;
int lth;
void insert(int x){
dis[np=++cnt]=dis[p=lst]+1;
Right[np]=1,lst=np;
for(;p&&!son[p][x];p=pre[p]) son[p][x]=np;
if(!p) return pre[np]=1,void();
q=son[p][x];
if(dis[q]==dis[p]+1) return pre[np]=q,void();
else{
dis[nq=++cnt]=dis[p]+1;
memcpy(son[nq],son[q],sizeof son[q]);
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
for(;p&&son[p][x]==q;p=pre[p]) son[p][x]=nq;
}
}
void build(){
lst=cnt=1;
scanf("%s",read_s);
lth=strlen(read_s);
for(int i=0;i<lth;++i) insert(read_s[i]-'a');
}
void build_(){
lst=cnt=1;
scanf("%s",read_s);
lth=strlen(read_s);
for(int i=lth-1;~i;--i) insert(read_s[i]-'a');
}
int s[MAXN<<1],v[MAXN<<1];
void sort(){
for(int i=1;i<=cnt;++i) ++v[dis[i]];
for(int i=1;i<=lth;++i) v[i]+=v[i-1];
for(int i=1;i<=cnt;++i) s[v[dis[i]]--]=i;
}
long long ans;
void DP(){
for(int i=cnt;i;--i){
int now=s[i],fth=pre[now];
Right[fth]+=Right[now];
ans+=1ll*(dis[now]-dis[fth])*Right[now]*(lth-Right[now]);
// int now=s[i],fth=pre[now],tmp=dis[now]-dis[fth];
// sum[now]+=Right[now]*tmp;
// ans+=sum[now]*Right[fth]+sum[fth]*Right[now];
// Right[fth]+=Right[now],sum[fth]+=sum[now];
}
}
#ifdef Flaze_naive
char tmp[MAXN<<1];
void dfs(int now,int stp){
puts(tmp);
for(int i=0;i<26;++i)
if(son[now][i])
tmp[stp]='a'+i,dfs(son[now][i],stp+1);
tmp[stp]=' ';
}
#endif
}SAM;
int main(){
SAM.build_();
#ifdef Flaze_naive
SAM.dfs(1,0);
#endif
SAM.sort();
SAM.DP();
printf("%lld",SAM.ans);
return 0;
}