bzoj1396&&2865 识别子串 后缀自动机+线段树
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
出现只有一次的是parent数上的叶子节点,endpos=1
所以只需要找endpos=1的节点minlen-maxlen之间对于一段的贡献放向去思考就可以了。
理解起来就是对于[endpos−maxlen+1,endpos−minlen+1][endpos−maxlen+1,endpos−minlen+1]中的每个子串都是单独存在的,所以这个RightRight集合贡献给他的答案就是这个点到endposendpos的长度。
对于[endpos−minlen,endpos][endpos−minlen,endpos]中的每个位置xx,贡献就是minlenminlen;
理解起来就是对于[endpos−minlen,endpos][endpos−minlen,endpos]中的每个子串显然是存在多个结束位置的,所以当前这个RightRight集合能够贡献给他的符合只出现一次且最短的,就是刚好跨过它的最小,即minlenminlen。
对于2865数据范围大了,而且还卡内存,不要面孔
纯自己手打
1 #pragma GCC optimize(2) 2 #pragma G++ optimize(2) 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<cstdio> 8 9 #define inf 1000000007 10 #define N 200007 11 using namespace std; 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 16 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 17 return x*f; 18 } 19 20 int n; 21 char ch[N]; 22 23 struct segment_tree 24 { 25 int tree[N<<2]; 26 inline void push_down(int p,int l,int r) 27 { 28 if(l==r)return; 29 int ls=p<<1,rs=p<<1|1; 30 tree[ls]=min(tree[ls],tree[p]); 31 tree[rs]=min(tree[rs],tree[p]); 32 } 33 void update(int p,int l,int r,int x,int y,int num) 34 { 35 if(x>y)return; 36 push_down(p,l,r); 37 if(l==x&&y==r) 38 { 39 tree[p]=min(tree[p],num); 40 return; 41 } 42 int mid=(l+r)>>1; 43 if(y<=mid)update(p<<1,l,mid,x,y,num); 44 else if(x>mid)update(p<<1|1,mid+1,r,x,y,num); 45 else update(p<<1,l,mid,x,mid,num),update(p<<1|1,mid+1,r,mid+1,y,num); 46 } 47 void build(int p,int l,int r) 48 { 49 if(l==r) 50 { 51 tree[p]=inf; 52 return; 53 } 54 int mid=(l+r)>>1; 55 build(p<<1,l,mid),build(p<<1|1,mid+1,r); 56 tree[p]=inf; 57 } 58 int query(int p,int l,int r,int x) 59 { 60 push_down(p,l,r); 61 if(l==r)return tree[p]; 62 int mid=(l+r)>>1; 63 if(x<=mid) return query(p<<1,l,mid,x); 64 else return query(p<<1|1,mid+1,r,x); 65 } 66 }A,B; 67 struct sam 68 { 69 int last,cnt,rt; 70 int fa[N],mx[N],c[N][26]; 71 sam(){last=cnt=rt=1;} 72 void extend(int x) 73 { 74 int p=last,np=last=++cnt;mx[np]=mx[p]+1; 75 while(p&&!c[p][x]) 76 { 77 c[p][x]=np; 78 p=fa[p]; 79 } 80 if(!p)fa[np]=rt; 81 else 82 { 83 int q=c[p][x]; 84 if(mx[q]==mx[p]+1)fa[np]=q; 85 else 86 { 87 int nq=++cnt;mx[nq]=mx[p]+1; 88 memcpy(c[nq],c[q],sizeof(c[q])); 89 fa[nq]=fa[q]; 90 fa[q]=fa[np]=nq; 91 while(c[p][x]==q)c[p][x]=nq,p=fa[p]; 92 } 93 } 94 } 95 bool flag[N]; 96 void build() 97 { 98 memset(flag,true,sizeof(flag)); 99 for (int i=1;i<=cnt;i++) 100 flag[fa[i]]=false; 101 for (int i=1;i<=cnt;i++) 102 if(flag[i]) 103 { 104 int l=mx[i]-mx[fa[i]],r=mx[i]; 105 A.update(1,1,n,1,l-1,r+1); 106 B.update(1,1,n,l,r,r-l+1); 107 } 108 } 109 }sam; 110 void solve() 111 { 112 for (int i=1;i<=n;i++) 113 printf("%d\n",min(A.query(1,1,n,i)-i,B.query(1,1,n,i))); 114 } 115 int main() 116 { 117 freopen("fzy.in","r",stdin); 118 freopen("fzy.out","w",stdout); 119 scanf("%s",ch+1);n=strlen(ch+1); 120 for (int i=1;i<=n;i++) 121 sam.extend(ch[i]-'a'); 122 A.build(1,1,n),B.build(1,1,n); 123 // cout<<1<<endl<<endl; 124 sam.build(),solve(); 125 }