BZOJ-1396: 识别子串

后缀自动机+线段树

先建出\(sam\),统计一遍每个点的\(right\)集合大小\(siz\),对于\(siz=1\)的点\(x\),他所代表的子串只会出现一次,设\(y=fa[x]\),则这个点代表的子串即为\((1...len[x]-len[y],len[x])\),对于子串\((len[x]-len[y],len[x])\)的每一个点,这个子串都是他的识别子串,长度固定\(len[y]+1\),而对于一个点\(i\in[1,len[x]-len[y]-1]\),子串\((i,len[x])\)一定是他的一个识别子串,长度\(len[x]+1-i\)。可以用两棵线段树分别存\(len[y]+1\)\(len[x]+1\),单点查询最小值得到答案

#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
struct xdt{
    int poi[maxn<<2],lazy[maxn<<2];
    void updata(int x){
        poi[x]=min(poi[x<<1],poi[x<<1|1]);
    }
    void pushdown(int x){
        if(!lazy[x]) return;
        poi[x<<1]=min(poi[x<<1],lazy[x]);
        lazy[x<<1]=lazy[x<<1]?min(lazy[x<<1],lazy[x]):lazy[x];
        poi[x<<1|1]=min(poi[x<<1|1],lazy[x]);
        lazy[x<<1|1]=lazy[x<<1|1]?min(lazy[x<<1|1],lazy[x]):lazy[x];
        lazy[x]=0;
    }
    void build(int l,int r,int now){
        poi[now]=0x7fffffff;
        if(l==r) return;
        int mid=l+r>>1;
        build(l,mid,now<<1);
        build(mid+1,r,now<<1|1);
    }
    void revise(int lc,int rc,int l,int r,int now,int z){
        if(lc==l&&rc==r){
            poi[now]=min(poi[now],z);
            if(lazy[now]==0) lazy[now]=z;
            else lazy[now]=min(lazy[now],z);
            return;
        }
        pushdown(now);
        int mid=lc+rc>>1;
        if(l<=mid) revise(lc,mid,l,min(mid,r),now<<1,z);
        if(r>mid) revise(mid+1,rc,max(mid+1,l),r,now<<1|1,z);
        updata(now);
    }
    int query(int lc,int rc,int x,int now){
        if(lc==rc) return poi[now];
        pushdown(now);
        int mid=lc+rc>>1;
        if(x<=mid) return query(lc,mid,x,now<<1);
        else return query(mid+1,rc,x,now<<1|1);
    }
}t1,t2;
struct SAM{
    int son[maxn][26],len[maxn],siz[maxn],fa[maxn],tax[maxn],a[maxn];
    int tot,last,n;
    char s[maxn];
    void insert(int x){
        int p=last,np=++tot;
        len[np]=len[p]+1;
        siz[np]=1;
        while(~p&&!son[p][x])
            son[p][x]=np,p=fa[p];
        if(p==-1)
            fa[np]=0;
        else{
            int q=son[p][x];
            if(len[q]==len[p]+1)
                fa[np]=q;
            else{
                int nq=++tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                fa[nq]=fa[q];
                len[nq]=len[p]+1;
                fa[q]=fa[np]=nq;
                while(~p&&son[p][x]==q)
                    son[p][x]=nq,p=fa[p];
            }
        }
        last=np;
    }
    void Qsort(){
        for(int i=0;i<=n;i++) tax[i]=0;
        for(int i=1;i<=tot;i++) tax[len[i]]++;
        for(int i=1;i<=n;i++) tax[i]+=tax[i-1];
        for(int i=1;i<=tot;i++) a[tax[len[i]]--]=i;
    }
    void ycl(){
        last=tot=0,fa[0]=-1;
        for(int i=1;i<=n;i++) insert(s[i]-'a');
        Qsort();
        for(int i=tot;i>=1;i--) siz[fa[a[i]]]+=siz[a[i]];
        t1.build(1,n,1),t2.build(1,n,1);
        for(int i=1;i<=tot;i++)
            if(siz[i]==1){
                int l=len[i]-len[fa[i]],r=len[i];
                t1.revise(1,n,l,r,1,r-l+1);
//              printf("->%d\n",t1.query(1,n,2,1));
                if(l!=1) t2.revise(1,n,1,l-1,1,r+1);
            }
    }
    void query(){
//              printf("->%d\n",t1.query(1,n,2,1));
        for(int i=1;i<=n;i++)
            printf("%d\n",min(t1.query(1,n,i,1),t2.query(1,n,i,1)-i));
    }
}sam;
int main(){
//  freopen(".in","r",stdin);
    scanf("%s",sam.s+1),sam.n=strlen(sam.s+1);
    sam.ycl();
    sam.query();
    return 0;
}

posted @ 2018-12-04 20:49  nianheng  阅读(332)  评论(0编辑  收藏  举报