bzoj 1396: 识别子串 (后缀自动机+线段树)
2017-01-12 21:33
423 查看
1396: 识别子串
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 308 Solved: 190
[Submit][Status][Discuss]
Description
Input
一行,一个由小写字母组成的字符串S,长度不超过10^5Output
L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.Sample Input
agoodcookcooksgoodfoodSample Output
12
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4
HINT
Source
[Submit][Status][Discuss]
题解:后缀自动机+线段树
这道题可以用来更新答案的状态一定的是|right|的大小等于1的状态,每个节点都对应着一些长度为[l[fa]+1,l[x]]的子串.我们按照拓扑序更新,并且需要维护right集合中右端点的位置st[x],然后对于每个|right|=1的状态,对于原串中st[x]-l[fa],st[x]位置都可以用l[fa]+1来更新最小值,如果只是这么做的话,我们发现更新到的位置十分有限,但是我们无法对于[l[fa]+1,l[x]]中的长度都进行更新。于是考虑什么情况是只用上面的方法更新不到的。
举例说明bbbc 对于第三个位置答案应该是bc,但是c在更新的时候只用1更新了自己,而第三个b在更新的时候用3更新了[1,3]这个区间。对于这种情况,我们用线段树再维护一个值,就是能更新到这个点的离他最近的点的位置,即用st[x]更新[st[x]-l[x]+1,st[x]-l[fa]-1]最后计算出距离更新答案即可。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 200003 using namespace std; int fa ,ch [30],l ,pos ,rt ,v ,n,inf; int p,np,nq,q,last,root,cnt,delta[N*4],tr[N*4],st ; char s ; void extend(int x) { int c=s[x]-'a'; p=last; np=last=++cnt; l[np]=l[p]+1; for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np; if (!p) fa[np]=root; else{ q=ch[p][c]; if (l[p]+1==l[q]) fa[np]=q; else { nq=++cnt; l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[nq])); fa[nq]=fa[q]; fa[q]=fa[np]=nq; for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; } } } void pushdown(int now) { if (delta[now]!=inf) { tr[now<<1]=min(tr[now<<1],delta[now]); tr[now<<1|1]=min(tr[now<<1|1],delta[now]); delta[now<<1]=min(delta[now<<1],delta[now]); delta[now<<1|1]=min(delta[now<<1|1],delta[now]); delta[now]=inf; } } void qjchange(int now,int l,int r,int ll,int rr,int v) { if (ll<=l&&r<=rr) { tr[now]=min(tr[now],v); delta[now]=min(delta[now],v); return; } int mid=(l+r)/2; pushdown(now); if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,v); if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,v); } int find(int now,int l,int r,int x) { if (l==r) return tr[now]; int mid=(l+r)/2; pushdown(now); if (x<=mid) return find(now<<1,l,mid,x); else return find(now<<1|1,mid+1,r,x); } namespace ac{ int delta[N*4],tr[N*4]; void clear() { memset(delta,127,sizeof(delta)); memset(tr,127,sizeof(tr)); } void pushdown(int now) { if (delta[now]!=inf) { tr[now<<1]=min(tr[now<<1],delta[now]); tr[now<<1|1]=min(tr[now<<1|1],delta[now]); delta[now<<1]=min(delta[now<<1],delta[now]); delta[now<<1|1]=min(delta[now<<1|1],delta[now]); delta[now]=inf; } } void qjchange(int now,int l,int r,int ll,int rr,int v) { if (ll<1||rr<1) return; if (ll<=l&&r<=rr) { tr[now]=min(tr[now],v); delta[now]=min(delta[now],v); return; } int mid=(l+r)/2; pushdown(now); if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,v); if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,v); } int find(int now,int l,int r,int x) { if (l==r) return tr[now]; int mid=(l+r)/2; pushdown(now); if (x<=mid) return find(now<<1,l,mid,x); else return find(now<<1|1,mid+1,r,x); } } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%s",s+1); n=strlen(s+1); root=last=++cnt; for (int i=1;i<=n;i++) extend(i); for (int i=1;i<=cnt;i++) v[l[i]]++; for (int i=1;i<=n;i++) v[i]+=v[i-1]; for (int i=cnt;i>=1;i--) pos[v[l[i]]--]=i; p=root; for (int i=1;i<=n;i++) { int c=s[i]-'a'; p=ch[p][c]; rt[p]=1; st[p]=i; //cout<<c<<" "<<p<<endl; } memset(tr,127,sizeof(tr)); memset(delta,127,sizeof(delta)); ac::clear(); inf=tr[0]; for (int i=cnt;i>=1;i--) { int mn=l[fa[pos[i]]]+1; int mn1=l[pos[i]]; rt[fa[pos[i]]]+=rt[pos[i]]; st[fa[pos[i]]]=st[pos[i]]; //cout<<st[pos[i]]<<" "<<l[pos[i]]<<" "<<l[fa[pos[i]]]+1<<endl; if(rt[pos[i]]==1){ qjchange(1,1,n,st[pos[i]]-mn+1,st[pos[i]],mn); ac::qjchange(1,1,n,max(1,st[pos[i]]-mn1+1),st[pos[i]]-mn,st[pos[i]]); } } for (int i=1;i<=n;i++) { int t=find(1,1,n,i); int t1=ac::find(1,1,n,i); if (t1!=inf) t=min(t,t1-i+1); if (t!=inf) printf("%d\n",t); else printf("0\n"); } }
相关文章推荐
- [BZOJ1396]识别子串(后缀自动机+线段树)
- [BZOJ1396]识别子串 后缀自动机+线段树
- 【BZOJ-1396&2865】识别子串&字符串识别 后缀自动机/后缀树组 + 线段树
- [后缀自动机 线段树] BZOJ 1396 识别子串 & BZOJ 2865 字符串识别
- BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)
- BZOJ 1396&&2865 识别子串[后缀自动机 线段树]
- BZOJ1396&2865 识别子串 【后缀自动机 + 线段树】
- BZOJ1396:识别子串(后缀自动机+单调队列)
- BZOJ 1396: 识别子串( 后缀数组 + 线段树 )
- 【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)
- 【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)
- 【bzoj2865】字符串识别 后缀自动机+线段树
- [BZOJ2865]字符串识别 后缀自动机+线段树
- bzoj 1396: 识别子串
- bzoj1396: 识别子串
- [BZOJ1396]识别子串
- ●BZOJ 1396 识别子串
- [BZOJ 1396] 识别子串
- BZOJ 1396:识别子串 SA+树状数组+单调队列
- BZOJ 2865 字符串识别 | 后缀数组 线段树