https://www.lydsy.com/JudgeOnline/problem.php?id=1396php
後綴自動機的parent樹上,若是不是葉子節點,那麼至少有兩個子節點ui
而一個狀態所表明子串的出現次數就是子樹中葉子節點的個數spa
因此只有葉子節點 即 |Right|=1的狀態 表明的子串 出現了1次code
咱們計算以每個位置爲子串右端點時,它對一些位置的貢獻blog
枚舉|Right|=1的狀態sget
令end=Right(s)string
那麼以end爲子串右端點,長度在[1,Max(parent(s))]的子串至少還會在s的父節點表示的狀態中出現it
因此在以end爲識別子串右端點時io
位置[end-Max(parent(s)),end]的最短長度爲Max(parent(s)+1ast
位置[end-Max(s)+1,end-Max(parent(s))]的最短長度爲 end-i+1
用兩棵線段樹維護
一棵直接維護最小值
另外一棵維護end+1的最小值,查詢的時候將結果-i
#include<cstdio> #include<cstring> #include<algorithm> #define N 100001 using namespace std; char s[N]; int ch[N<<1][26],tot=1; int fa[N<<1],len[N<<1]; int siz[N<<1]; int last=1,p,q,np,nq; int leaf[N]; int v[N],sa[N<<1]; struct Segment { int mx[N<<2]; int tag[N<<2]; void down(int k) { mx[k<<1]=min(mx[k<<1],tag[k]); mx[k<<1|1]=min(mx[k<<1|1],tag[k]); tag[k<<1]=min(tag[k<<1],tag[k]); tag[k<<1|1]=min(tag[k<<1|1],tag[k]); tag[k]=2e9; } void build(int k,int l,int r) { mx[k]=tag[k]=2e9; if(l==r) return; int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void change(int k,int l,int r,int opl,int opr,int w) { if(l>=opl && r<=opr) { mx[k]=min(mx[k],w); tag[k]=min(tag[k],w); return; } int mid=l+r>>1; if(tag[k]!=2e9) down(k); if(opl<=mid) change(k<<1,l,mid,opl,opr,w); if(opr>mid) change(k<<1|1,mid+1,r,opl,opr,w); mx[k]=min(mx[k<<1],mx[k<<1|1]); } int query(int k,int l,int r,int x) { if(l==r) return mx[k]; int mid=l+r>>1; if(tag[k]!=2e9) down(k); if(x<=mid) return query(k<<1,l,mid,x); return query(k<<1|1,mid+1,r,x); } }; Segment tr1,tr2; void extend(int c) { len[np=++tot]=len[last]+1; siz[tot]=1; for(p=last;p && !ch[p][c];p=fa[p]) ch[p][c]=np; if(!p) fa[np]=1; else { q=ch[p][c]; if(len[q]==len[p]+1) fa[np]=q; else { nq=++tot; fa[nq]=fa[q]; memcpy(ch[nq],ch[q],sizeof(ch[nq])); fa[q]=fa[np]=nq; len[nq]=len[p]+1; for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; } } last=np; } int main() { scanf("%s",s+1); int n=strlen(s+1); for(int i=1;i<=n;++i) { leaf[i]=tot+1; extend(s[i]-'a'); } for(int i=1;i<=tot;++i) v[len[i]]++; for(int i=1;i<=n;++i) v[i]+=v[i-1]; for(int i=1;i<=tot;++i) sa[v[len[i]]--]=i; int x; for(int i=tot;i;--i) { x=sa[i]; siz[fa[x]]+=siz[x]; } tr1.build(1,1,n); tr2.build(1,1,n); int l,r,end; for(int x=2;x<=tot;++x) if(siz[x]==1) { l=len[fa[x]]; r=len[x]; end=len[x]; tr1.change(1,1,n,end-l,end,l+1); tr2.change(1,1,n,end-r+1,end-l,end+1); } int a,b; for(int i=1;i<=n;++i) { a=tr1.query(1,1,n,i); b=tr2.query(1,1,n,i)-i; printf("%d\n",min(a,b)); } return 0; }