BZOJ1396:识别子串(SAM)
Description
Input
一行,一个由小写字母组成的字符串S,长度不超过10^5
Output
L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.
Sample Input
agoodcookcooksgoodfood
Sample Output
1
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4
Solution
1A挺开心的省得调了
对于SAM上的每一个节点,我们只需要考虑right集合大小为1的
设一个right集合大小为1的点结束点在endpos,有效长度为[l,r]
那么对于区间[endpos-r+1,endpos-l+1],这个点的贡献为endpos-i+1,用一颗线段树维护endpos+1,i最后计算贡献
对于区间[endpos-l+1,endpos],这个点的贡献为l,再开一颗线段树维护l
最后扫一遍单点查询最小值就好了
标记永久化好像非常短还好写= =
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (200000+1000) 5 using namespace std; 6 7 char s[N]; 8 int Ans,n; 9 10 struct SGT 11 { 12 int Segt[N<<1]; 13 SGT(){memset(Segt,0x7f,sizeof(Segt));} 14 15 void Update(int now,int l,int r,int l1,int r1,int k) 16 { 17 if (r<l1 || l>r1) return; 18 if (l1<=l && r<=r1){Segt[now]=min(Segt[now],k);return;} 19 int mid=(l+r)>>1; 20 Update(now<<1,l,mid,l1,r1,k); Update(now<<1|1,mid+1,r,l1,r1,k); 21 } 22 void Query(int now,int l,int r,int x) 23 { 24 Ans=min(Ans,Segt[now]); 25 if (l==r) return; 26 int mid=(l+r)>>1; 27 if (x<=mid) Query(now<<1,l,mid,x); 28 else Query(now<<1|1,mid+1,r,x); 29 } 30 }SGT[2]; 31 32 struct SAM 33 { 34 int fa[N],son[N][28],right[N],step[N],End[N],od[N],wt[N]; 35 int p,q,np,nq,last,cnt; 36 SAM(){last=++cnt;} 37 38 void Insert(int x,int pos) 39 { 40 p=last; last=np=++cnt; step[np]=step[p]+1; right[np]=1; End[np]=pos; 41 while (p && !son[p][x]) son[p][x]=np,p=fa[p]; 42 if (!p) fa[np]=1; 43 else 44 { 45 q=son[p][x]; 46 if (step[p]+1==step[q]) fa[np]=q; 47 else 48 { 49 nq=++cnt; step[nq]=step[p]+1; 50 memcpy(son[nq],son[q],sizeof(son[q])); 51 fa[nq]=fa[q]; fa[q]=fa[np]=nq; 52 while (son[p][x]==q) son[p][x]=nq,p=fa[p]; 53 } 54 } 55 } 56 void Init() 57 { 58 int len=strlen(s+1); 59 for (int i=1; i<=cnt; ++i) wt[step[i]]++; 60 for (int i=1; i<=len; ++i) wt[i]+=wt[i-1]; 61 for (int i=cnt; i>=1; --i) od[wt[step[i]]--]=i; 62 for (int i=cnt; i>=1; --i) right[fa[od[i]]]+=right[od[i]]; 63 } 64 void Solve() 65 { 66 for (int i=1; i<=cnt; ++i) 67 if (right[i]==1) 68 { 69 SGT[0].Update(1,1,n,End[i]-step[i]+1,End[i]-step[fa[i]],End[i]+1); 70 SGT[1].Update(1,1,n,End[i]-step[fa[i]],End[i],step[fa[i]]+1); 71 } 72 for (int i=1; i<=n; ++i) 73 { 74 Ans=0x7fffffff; 75 SGT[0].Query(1,1,n,i); Ans-=i; 76 SGT[1].Query(1,1,n,i); 77 printf("%d\n",Ans); 78 } 79 } 80 }SAM; 81 82 int main() 83 { 84 scanf("%s",s+1); 85 n=strlen(s+1); 86 for (int i=1; i<=n; ++i) 87 SAM.Insert(s[i]-'a',i); 88 SAM.Init(); 89 SAM.Solve(); 90 }