1396: 识别子串
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 451 Solved: 290
[Submit][Status][Discuss]
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
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4
HINT
Source
首先我们发现要找子串,想到用后缀自动机。
显然只出现一次的子串为right=1的节点(即结束节点只有一个)。对于这些节点,我们考虑对答案的贡献。
对于一个节点显然endpos-maxlen+1到endpos-minlen+1的子串是唯一的贡献为endpos-i+1。
对于endpos-minlen+1到endpos的节点,子串不唯一,我们需要将他向前延伸到endpos-minlen+1的点,贡献为minlen。
维护两棵线段树即可。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 #define maxn 800005 8 using namespace std; 9 struct data { 10 int son[maxn][30],link[maxn],step[maxn],cnt,last; 11 int v[maxn],pos[maxn],size[maxn],endpos[maxn]; 12 data() {last=cnt=1;} 13 void extend(int c,int x) { 14 int p=last,np=last=++cnt; 15 step[np]=step[p]+1;size[np]=1;endpos[np]=x; 16 while(p&&!son[p][c]) son[p][c]=np,p=link[p]; 17 if(!p) link[np]=1; 18 else { 19 int q=son[p][c]; 20 if(step[q]==step[p]+1) link[np]=q; 21 else { 22 int nq=++cnt; 23 memcpy(son[nq],son[q],sizeof(son[q])); 24 link[nq]=link[q]; 25 link[q]=link[np]=nq; 26 step[nq]=step[p]+1; 27 while(son[p][c]==q&&p) son[p][c]=nq,p=link[p]; 28 } 29 } 30 } 31 void pre() { 32 for(int i=1;i<=cnt;i++) v[step[i]]++; 33 for(int i=1;i<=cnt;i++) v[i]+=v[i-1]; 34 for(int i=cnt;i;i--) pos[v[step[i]]--]=i; 35 for(int i=cnt;i;i--) { 36 int x=pos[i]; 37 size[link[x]]+=size[x]; 38 endpos[link[x]]=max(endpos[link[x]],endpos[x]); 39 } 40 } 41 struct tmp{ 42 int minx[maxn],tag[maxn]; 43 tmp(){memset(minx,97,sizeof(minx));for(int i=1;i<maxn;i++) tag[i]=2147483647;} 44 void pushup(int o) { 45 int ls=o<<1,rs=ls+1; 46 minx[o]=min(minx[ls],minx[rs]); 47 } 48 void pushdown(int o) { 49 int ls=o<<1,rs=ls+1; 50 minx[ls]=min(tag[o],minx[ls]);minx[rs]=min(minx[rs],tag[o]); 51 tag[ls]=min(tag[ls],tag[o]);tag[rs]=min(tag[rs],tag[o]); 52 tag[o]=2147483647; 53 } 54 void update(int l,int r,int o,int L,int R,int val) { 55 pushdown(o); 56 if(L<=l&&R>=r) {tag[o]=min(tag[o],val);minx[o]=min(minx[o],val);return;} 57 int mid=l+r>>1,ls=o<<1,rs=ls+1; 58 if(L<=mid)update(l,mid,ls,L,R,val); 59 if(R>mid) update(mid+1,r,rs,L,R,val); 60 pushup(o); 61 } 62 int query(int l,int r,int o,int x) { 63 pushdown(o); 64 if(l==r) return minx[o]; 65 int mid=l+r>>1,ls=o<<1,rs=ls+1; 66 if(x<=mid) return query(l,mid,ls,x); 67 if(x>mid) return query(mid+1,r,rs,x); 68 } 69 }t1,t2; 70 void work(int x) { 71 for(int i=1;i<=cnt;i++) { 72 if(size[i]!=1) continue; 73 int maxlen=step[i],minlen=step[link[i]]+1; 74 t1.update(1,x,1,endpos[i]-maxlen+1,endpos[i]-minlen+1,endpos[i]+1); 75 t2.update(1,x,1,endpos[i]-minlen+1,endpos[i],minlen); 76 } 77 for(int i=1;i<=x;i++) { 78 int a1=t1.query(1,x,1,i)-i,a2=t2.query(1,x,1,i); 79 printf("%d\n",min(a1,a2)); 80 } 81 } 82 }sam; 83 char ch[maxn]; 84 int main() { 85 scanf("%s",ch+1); 86 int len=strlen(ch+1); 87 for(int i=1;i<=len;i++) sam.extend(ch[i]-‘a‘,i); 88 sam.pre(); 89 sam.work(len); 90 }