【BZOJ1396】識別子串 - 字尾自動機+線段樹
阿新 • • 發佈:2018-12-17
題意:
Description
Input
一行,一個由小寫字母組成的字串S,長度不超過10^5Output
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 }