按照我自己对静态的后缀树理解,写出如下代码:
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define ll long long
#define ull unsigned ll
#define db double
#define ldb long db
#define mp make_pair
#define fi first
#define se second
#define pii pair<int,int>
#define pbI push_back
#define inf 2e9
#define mdI int mid=(l+r)>>1
#define lowbit(x) ((x)&(-(x)))
#define rep(a,b,c) for(int a=(b);a<=(c);a++)
#define vep(a,b,c) for(int a=(b);a>=(c);a--)
#define MAXN 500010
#define gint __int128
#define MOD 1000000007//998244353
int qread(){
char o=getchar();int f=1,x=0;
for(;!isdigit(o);o=getchar())if(o=='-')f*=-1;
for(;isdigit(o);o=getchar())x=x*10+o-'0';
return f*x;
}
void chmx(db &x,db y){if(y>x)x=y;}
void chmx(int &x,int y){if(y>x)x=y;}
void chmi(int &x,int y){if(y<x)x=y;}
ll qp(ll a,ll b,ll p=MOD){
ll bs=a,rs=1;while(b){if(b&1)rs=rs*bs%p;bs=bs*bs%p;b>>=1;}return rs;
}
bool FLA;
namespace SA{
int n,m,w,ork[MAXN<<1],id[MAXN],cnt[MAXN];
int rk[MAXN<<1],sa[MAXN],he[MAXN];string s;
int Fil(){
memcpy(ork,rk,sizeof(rk));
int p=0;rep(i,1,n){if(ork[sa[i]]==ork[sa[i-1]]&&ork[sa[i]+w]==ork[sa[i-1]+w]){rk[sa[i]]=p;}else{rk[sa[i]]=++p;}}
return p;
}
void Sort(int O){
memset(cnt,0,sizeof(cnt));memcpy(id,sa,sizeof(sa));
rep(i,1,n)cnt[rk[id[i]+O]]++;
rep(i,1,m)cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--)sa[cnt[rk[id[i]+O]]--]=id[i];
}
int st[20][MAXN],wh[20][MAXN],Lg2[MAXN];
int ch[MAXN<<2][31],L[MAXN<<2],R[MAXN<<2],Va[MAXN<<2],Cnt,sz[MAXN<<2];
int ren(int &x){return x?x:(x=++Cnt);}
pii que(int l,int r){
if(l==r){return mp(st[0][l],l);}
int k=Lg2[r-l+1];
if(st[k][l]<=st[k][r-(1<<k)+1]){return mp(st[k][l],wh[k][l]);}
else{return mp(st[k][r-(1<<k)+1],wh[k][r-(1<<k)+1]);}
}
void build(int x,int l,int r){
L[x]=l,R[x]=r,sz[x]=r-l+1;
if(l==r){Va[x]=n-sa[l]+1;return;}
int Cm=0,l1=l,V0=inf;
while(l1<r){
pii a=que(l1,r-1);
if(a.fi<=V0){V0=a.fi;}else{break;}
Cm++;
build(ren(ch[x][Cm]),l1,a.se);
l1=a.se+1;
}
Va[x]=V0;
if(l1<=r)build(ren(ch[x][++Cm]),l1,r);
assert(Cm<=30);
}
ll ans=0;
void dfs(int x){
//cerr<<"Id:"<<x<<" "<<L[x]<<" "<<R[x]<<" "<<Va[x]<<endl;
//rep(i,1,26){
//if(!ch[x][i])break;
//cerr<<"Son:"<<ch[x][i]<<" "<<L[ch[x][i]]<<" "<<R[ch[x][i]]<<" "<<Va[ch[x][i]]<<endl;
//}
rep(i,1,30){
if(ch[x][i]==0)break;
dfs(ch[x][i]);
ans+=((ll)sz[ch[x][i]])*(n-sz[ch[x][i]])*abs(Va[x]-Va[ch[x][i]]);
}
}
void solve(string t){
memset(rk,0,sizeof(rk));memset(sa,0,sizeof(sa));memset(he,0,sizeof(he));
n=t.size(),m=127,w=0;s=" "+t;
rep(i,1,n)sa[i]=i,rk[i]=s[i];
Sort(0);
Fil();for(w=1;w<=n;w<<=1){Sort(w);Sort(0);m=Fil();}
int le=0;
rep(i,1,n){
if(rk[i]==n)continue;
if(le)le--;while(s[i+le]==s[sa[rk[i]+1]+le])le++;
he[rk[i]]=le;
}
rep(i,1,n)st[0][i]=he[i],wh[0][i]=i;
Lg2[1]=0;rep(i,2,n)Lg2[i]=Lg2[i>>1]+1;
rep(i,1,19){
rep(j,1,n-(1<<i)+1){
if(st[i-1][j]<=st[i-1][j+(1<<i-1)]){st[i][j]=st[i-1][j],wh[i][j]=wh[i-1][j];}
else{st[i][j]=st[i-1][j+(1<<i-1)],wh[i][j]=wh[i-1][j+(1<<i-1)];}
}
}
Cnt=1;build(1,1,n);dfs(1);cout<<ans;
//assert(Cnt<2*MAXN);
}
}
string s;
bool FLB;
signed main(){
cerr<<((&FLB)-(&FLA))/1024.0/1024<<endl;
cin>>s;
SA::solve(s);
}
大概的意思是,对于sa[l...r]这段区间,以height[l...r-1]的所有最小值把区间分割开来,递归进行。L,R表示区间端点,Va为lcp(sa[l..r])。
height在这段区间内在k取最小值va,当且仅当这些后缀有公共前缀长度为va,后缀sa[k]和sa[k+1]的第va+1的点不一样,这种不一样理应至多有26次,但是我开到30才正确,否则Wa On 7和13,这是为何?