1. 程式人生 > >【BZOJ1396】識別子串 - 字尾自動機+線段樹

【BZOJ1396】識別子串 - 字尾自動機+線段樹

題意:

Description

Input

一行,一個由小寫字母組成的字串S,長度不超過10^5

Output

L行,每行一個整數,第i行的資料表示關於S的第i個元素的最短識別子串有多長.

題解:

先建出SAM,顯然right集合大小為1的子串,即在parent樹上的葉子節點可以作為識別子串;

考慮一個這樣的子串會對哪些區間產生影響:

設$l=max[fa[s]]$,$r=max[s]$,顯然這個子串出現的位置就是$r$,所以對區間$[1,r]$都有影響;

但是其中有一段是被$fa[s]$包含的,因此貢獻不同,具體來說就是:

在區間$[1,l-1]$中貢獻為$r-i+1$;

在區間$[l,r]$中貢獻為$r-l+1$;

這裡手推一下就好;

因此開兩棵線段樹維護修改最小值即可。

程式碼:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 #include<set>
 8 #define inf 0x7f7f7f7f
 9 #define eps 1e-9
10
#define mp make_pair 11 using namespace std; 12 typedef long long ll; 13 typedef double db; 14 int n,l,r,last=1,rt=1,tot=1,son[200001][26],fa[200001],mx[200001]; 15 bool ch[200001]; 16 char s[100001]; 17 struct seg{ 18 int t[2000001]; 19 seg(){ 20 memset(t,0x7f,sizeof(t)); 21 } 22 void pd(int
u){ 23 if(t[u]!=inf){ 24 t[u*2]=min(t[u*2],t[u]); 25 t[u*2+1]=min(t[u*2+1],t[u]); 26 t[u]=inf; 27 } 28 } 29 void updata(int l,int r,int u,int L,int R,int x){ 30 if(L>R)return; 31 if(L<=l&&r<=R){ 32 t[u]=min(t[u],x); 33 return; 34 } 35 pd(u); 36 int mid=(l+r)/2; 37 if(L<=mid)updata(l,mid,u*2,L,R,x); 38 if(mid<R)updata(mid+1,r,u*2+1,L,R,x); 39 } 40 int query(int l,int r,int u,int p){ 41 if(l==r)return t[u]; 42 pd(u); 43 int mid=(l+r)/2; 44 if(p<=mid)return query(l,mid,u*2,p); 45 else return query(mid+1,r,u*2+1,p); 46 } 47 }t1,t2; 48 void extend(int ch){ 49 int p=last,np=++tot; 50 mx[np]=mx[p]+1; 51 for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np; 52 if(!p)fa[np]=rt; 53 else{ 54 int q=son[p][ch]; 55 if(mx[q]==mx[p]+1)fa[np]=q; 56 else{ 57 int nq=++tot; 58 mx[nq]=mx[p]+1; 59 memcpy(son[nq],son[q],sizeof(son[q])); 60 fa[nq]=fa[q]; 61 fa[q]=fa[np]=nq; 62 for(;p&&son[p][ch]==q;p=fa[p])son[p][ch]=nq; 63 } 64 } 65 last=np; 66 } 67 int main(){ 68 scanf("%s",s); 69 n=strlen(s); 70 for(int i=0;i<n;i++)extend(s[i]-'a'); 71 for(int i=1;i<=tot;i++){ 72 if(fa[i])ch[fa[i]]=true; 73 } 74 for(int i=1;i<=tot;i++){ 75 if(!ch[i]){ 76 l=mx[i]-mx[fa[i]],r=mx[i]; 77 t1.updata(1,n,1,1,l-1,r+1); 78 t2.updata(1,n,1,l,r,r-l+1); 79 } 80 } 81 for(int i=1;i<=n;i++){ 82 printf("%d\n",min(t1.query(1,n,1,i)-i,t2.query(1,n,1,i))); 83 } 84 return 0; 85 }