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 }
posted @ 2018-07-26 11:00  Refun  阅读(223)  评论(0编辑  收藏  举报