ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

XX在进行字符串研究的时候,遇到了一个十分棘手的问题。

在这个问题中,给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件:

1、i≤K≤j。

2、子串T只在S中出现过一次。

例如,S="banana",K=5,则关于第K位的识别子串有"nana","anan","anana","nan","banan"和"banana"。

现在,给定S,XX希望知道对于S的每一位,最短的识别子串长度是多少,请你来帮助他。

Input

仅一行,输入长度为N的字符串S。

Output

输出N行,每行一个整数,第i行的整数表示对于第i位的最短识别子串长度。

 

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

 

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

 

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

 

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

此题卡内存...

 

#include<cstdio>
#include<cstring>
const int N=900005;
int nx[N][26],fa[N],l[N],r[N],t[N],q[N],ql=0,qr=0,d[N],ptr=1,pv=1,len=0;
char s[500050];
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[1048576],mn2[1048576];
inline void mins(int&a,int b){if(a>b)a=b;}
void setmin(int l,int r,int x,int*mn){
    for(l+=524289,r+=524291;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[500055];
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<524288;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+524290];
        mins(ans[i],mn2[i+524290]-i);
    }
    for(int i=1;i<=len;i++)printf("%d\n",ans[i]);
    return 0;
}

 

posted on 2016-05-16 22:03  nul  阅读(598)  评论(0编辑  收藏  举报