SAM上的状态i表示的是以某个位置x
x
为右端点,以x−len[i]+1....x−mi[i]+1的位置为左端的一堆子串
siz[i]
s
i
z
[
i
]
则表示i状态的出现次数
mi[i]
m
i
[
i
]
就表示root到状态i的最短距离,可以建完SAM后bfs一遍
也可以在建SAM时,当一个状态u
u
向状态now连一条字符边时,mi[now]=min(mi[now],mi[u]+1)
m
i
[
n
o
w
]
=
m
i
n
(
m
i
[
n
o
w
]
,
m
i
[
u
]
+
1
)
在len[u]+1<len[v]
l
e
n
[
u
]
+
1
<
l
e
n
[
v
]
时,mi[np]=mi[v],mi[v]=mi[np]+1
m
i
[
n
p
]
=
m
i
[
v
]
,
m
i
[
v
]
=
m
i
[
n
p
]
+
1
mi
m
i
就搞定了
在建SAM时,siz[now]=1,siz[np]=0
s
i
z
[
n
o
w
]
=
1
,
s
i
z
[
n
p
]
=
0
然后siz[fa[i]]+=siz[i]
s
i
z
[
f
a
[
i
]
]
+
=
s
i
z
[
i
]
因为i状态是fa[i]状态的一个子集 求出所有的siz[i]==1
s
i
z
[
i
]
==
1
的状态,然后在区间fro[i]−mi[i]+1...fro[i]
f
r
o
[
i
]
−
m
i
[
i
]
+
1...
f
r
o
[
i
]
对mi[i]
m
i
[
i
]
取min,fro[i]
f
r
o
[
i
]
是i状态的右端点
由于一个子串T
T
包含一个识别子串T′时,T
T
也是一个子串
所以最后要ans[i]=min(ans[i],ans[i+1]+1)(因为有些位置可能没被覆盖)
#include <cstdio>#include <cstring>#include <iostream>#define min(a,b) ((a)<(b)?(a):(b))#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxN=2e5+10,maxK=26;
char s[maxN];
int n,i,tr[maxN*4],ans[maxN],ans1,l,r,zl,y;
void find(intx,int head,int tail){
if(l<=head && tail<=r){
if (zl==0) tr[x]=min(tr[x],y);
if (zl==1) ans1=min(ans1,tr[x]);
return;
}
tr[x*2]=min(tr[x*2],tr[x]);
tr[x*2+1]=min(tr[x*2+1],tr[x]);
int mid=(head+tail)/2;
if (l<=mid) find(x*2,head,mid);
if (mid<r) find(x*2+1,mid+1,tail);
}
struct sam{
int len[maxN],mi[maxN],siz[maxN],a[maxN],cnt[maxN],
ch[maxN][maxK],p,now,last,u,v,pre[maxN],np,fro[maxN],x,i;
int newnode(intx){
len[++p]=x,pre[p]=siz[p]=mi[p]=0;
fo(i,0,25)
ch[p][i]=0;
return p;
}
void init(){
p=0;
newnode(0);
last=p;
}
void add(int c,int i){
now=newnode(len[last]+1),mi[now]=len[now],fro[now]=i;
for(u=last;u && !ch[u][c];u=pre[u]) //细节
ch[u][c]=now,mi[now]=min(mi[u]+1,mi[now]);
if (!u) pre[now]=1;else{
v=ch[u][c];
if (len[u]+1==len[v]) pre[now]=v;else{
np=newnode(len[u]+1),memcpy(ch[np],ch[v],sizeof(ch[np]));//细节
pre[np]=pre[v],pre[v]=pre[now]=np,mi[np]=mi[v],mi[v]=len[u]+2,
fro[np]=fro[v];
for(;u && ch[u][c]==v;u=pre[u]) ch[u][c]=np;
}
}
last=now,siz[now]=1;
}
void work(){
fo(i,1,p) cnt[len[i]]++;
fo(i,1,p) cnt[i]+=cnt[i-1];
fo(i,1,p)
a[cnt[len[i]]--]=i;
fd(i,p,1)
siz[pre[a[i]]]+=siz[a[i]];
fo(i,1,p){
if (siz[i]==1){
r=fro[i],y=mi[i],l=r-y+1,zl=0,
find(1,1,n);
}
}
}
}run;
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%s",s+1),n=strlen(s+1);
run.init();
fo(i,1,n)
run.add(s[i]-'a',i);
fo(i,1,4*n) tr[i]=n;
run.work();
fo(i,1,n)
l=r=i,zl=1,ans1=n,find(1,1,n),ans[i]=ans1;
fd(i,n-1,1)
ans[i]=min(ans[i],ans[i+1]+1);
fo(i,1,n)
printf("%d\n",ans[i]);
}