题意:
题解:
SAM+线段树
先建出SAM,根据题意,只有
e
n
d
p
o
s
endpos
endpos集合大小为
1
1
1的结点才能造成贡献。
对于每一个
e
n
d
p
o
s
endpos
endpos集合大小为
1
1
1的我们都能算出
m
a
x
l
e
n
maxlen
maxlen和
m
i
n
l
e
n
minlen
minlen,显然
Ⅱ
Ⅱ
Ⅱ区域内每个点的贡献就是
Ⅱ
Ⅱ
Ⅱ区域的长度,
Ⅰ
Ⅰ
Ⅰ区域内每个点的贡献就是到
Ⅱ
Ⅱ
Ⅱ区域的距离加上
Ⅱ
Ⅱ
Ⅱ区域的长度。
建两棵线段树即可,一个修改
Ⅰ
Ⅰ
Ⅰ区域,一个修改
Ⅱ
Ⅱ
Ⅱ区域。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+50;
const int INF = 0x3f3f3f3f;
struct Tree{
struct Seg{
int l,r,mi,lazy;
}seg[MAXN<<2];
inline void pushup(int rt){ seg[rt].mi=min(seg[rt<<1].mi,seg[rt<<1|1].mi); }
inline void pushdown(int rt){
if(seg[rt].lazy<INF){
seg[rt<<1].mi=min(seg[rt<<1].mi,seg[rt].lazy);
seg[rt<<1].lazy=min(seg[rt<<1].lazy,seg[rt].lazy);
seg[rt<<1|1].mi=min(seg[rt<<1|1].mi,seg[rt].lazy);
seg[rt<<1|1].lazy=min(seg[rt<<1|1].lazy,seg[rt].lazy);
seg[rt].lazy=INF;
}
}
inline void Build(int rt,int l,int r){
seg[rt].mi=seg[rt].lazy=INF;
seg[rt].l=l,seg[rt].r=r;
if(l==r) return;
int mid = (l+r)>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
}
inline void update(int rt,int l,int r,int val){
if(seg[rt].r<l || seg[rt].l>r || l>r) return;
if(l<=seg[rt].l && seg[rt].r<=r){
seg[rt].mi = min(seg[rt].mi,val);
seg[rt].lazy = min(seg[rt].lazy,val);
return;
}
int mid = (seg[rt].l+seg[rt].r)>>1;
pushdown(rt);
if(l<=mid) update(rt<<1,l,r,val);
if(r>mid) update(rt<<1|1,l,r,val);
pushup(rt);
}
}T1,T2;
int ans[MAXN];
char s[MAXN];
int pos[MAXN],a[MAXN],c[MAXN];
int nxt[MAXN][26],fa[MAXN],len[MAXN];
int endpos[MAXN];
int last=1,tot=1,n;
void Query(int rt,int l,int r){
if(l==r){
ans[l] = min(T1.seg[rt].mi-l,T2.seg[rt].mi);
return;
}
int mid = (l+r)>>1;
T1.pushdown(rt);
T2.pushdown(rt);
Query(rt<<1,l,mid);
Query(rt<<1|1,mid+1,r);
}
inline void Insert(int x,int k){
int p=last,np=++tot;
last=np,len[np]=len[p]+1;
for(;p&&!nxt[p][x];p=fa[p]) nxt[p][x]=np;
if(!p) fa[np]=1;
else{
int q=nxt[p][x];
if(len[p]+1==len[q]) fa[np]=q;
else{
int nq=++tot;
len[nq]=len[p]+1;
memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for(;nxt[p][x]==q;p=fa[p]) nxt[p][x]=nq;
}
}
pos[np]=k;
endpos[np]=1;
}
inline void Sort(){
for(int i=1;i<=tot;i++) ++c[len[i]];
for(int i=1;i<=tot;i++) c[i]+=c[i-1];
for(int i=1;i<=tot;i++) a[c[len[i]]--]=i;
}
int main(){
scanf("%s",s+1);
n = strlen(s+1);
for(int i=1;i<=n;i++) Insert(s[i]-'a',i);
Sort();
T1.Build(1,1,n); T2.Build(1,1,n);
for(int i=tot;i;i--){
int x = a[i];
endpos[fa[x]] += endpos[x];
if(x==1 || endpos[x]>1) continue;
int l = pos[x]-len[x]+1;
int r = pos[x]-(len[fa[x]]+1)+1;
T1.update(1,l,r-1,pos[x]+1);
T2.update(1,r,pos[x],pos[x]-r+1);
}
Query(1,1,n);
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}