您的位置:首页 > 其它

bzoj1396 识别子串

2016-05-14 22:37 417 查看


建SAM,只有right集大小为1的节点对答案有贡献,

若其出现位置右端点为r,此节点可接受的最短串长为x,最长串长为y,

则对(r-x,r]用x更新最小值,对r-k (y<k≤x)则用k更新最小值

用两棵线段树维护答案,分别处理以上两种情况

#include<cstdio>
#include<cstring>
const int N=200005;
int nx
[26],fa
,l
,r
,t
,q
,ql=0,qr=0,d
,ptr=1,pv=1,len=0;
char s[100005];
void ins(int w,int pos){
int p=pv,np=++ptr;
t[np]=1;
r[np]=pos;
l[np]=l[p]+1;
while(p&&!nx[p][w])nx[p][w]=np,p=fa[p];
if(!p)fa[np]=1;
else{
int q=nx[p][w];
if(l[q]==l[p]+1)fa[np]=q;
else{
int nq=++ptr;
memcpy(nx[nq],nx[q],sizeof(nx[0]));
l[nq]=l[p]+1;
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
while(p&&nx[p][w]==q)nx[p][w]=nq,p=fa[p];
}
}
pv=np;
}
void build(){
for(int i=1;i<=ptr;i++)++d[fa[i]];
for(int i=1;i<=ptr;i++)if(!d[i])q[qr++]=i;
while(ql!=qr){
int w=q[ql++];
int u=fa[w];
if(!u)continue;
t[u]+=t[w];
r[u]=r[w];
if(!--d[u])q[qr++]=u;
}
}
int mn[262144],mn2[262144];
inline void mins(int&a,int b){if(a>b)a=b;}
void setmin(int l,int r,int x,int*mn){
for(l+=131073,r+=131075;l^r^1;l>>=1,r>>=1){
if(~l&1)mins(mn[l^1],x);
if(r&1)mins(mn[r^1],x);
}
}
int ans[100005];
int main(){
memset(mn,63,sizeof(mn));
memset(mn2,63,sizeof(mn2));
scanf("%s",s);
for(len=0;s[len];++len)ins(s[len]-'a',len+1);
build();
for(int i=2;i<=ptr;i++)if(t[i]==1){
int ml=l[fa[i]];
setmin(r[i]-ml+1,r[i],ml+1,mn);
setmin(r[i]-l[i]+1,r[i]-ml,r[i]+1,mn2);
}
for(int i=1;i<131072;i++){
int lc=i<<1,rc=lc^1;
mins(mn[lc],mn[i]),mins(mn[rc],mn[i]);
mins(mn2[lc],mn2[i]),mins(mn2[rc],mn2[i]);
}
for(int i=1;i<=len;i++){
ans[i]=mn[i+131074];
mins(ans[i],mn2[i+131074]-i);
}
for(int i=1;i<=len;i++)printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: