BZOJ1396识别子串&BZOJ2865字符串识别(后缀自动机)

Posted 小蒟蒻yyb的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1396识别子串&BZOJ2865字符串识别(后缀自动机)相关的知识,希望对你有一定的参考价值。

【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)

题面

自从有了DBZOJ
终于有地方交权限题了

题解

很明显,只出现了一次的串
\(SAM\)\(right/endpos\)集合大小一定为\(1\)
换句话说,在\(parent\)树上是叶子节点
找到所有这样的节点,
假设它的\(len=r\),它父亲的\(len=p\),它的结束位置为显然就是\(r\)
\(l=r-p\)
\(r\)结尾,
并且只出现了一次的串的左端点
\(1..l\),那么,他们的答案可以更新为\(r+1-i\)
剩下的位置\(l+1..r\),他们无法作为左端点,只能包含在这些串中
于是找到一个最短的包含他们的串\(S[l..r]\)
所以,这段区间的答案可以更新为\(r-l+1\)

显然不好一起维护,
于是开两棵线段树,一个维护\(r+1-i\),先不考虑\(i\),最后减去就好
另一个直接维护\(r-l+1\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define lson (now<<1)
#define rson (now<<1|1)
#define MAX 111111
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int n;
bool vis[MAX<<1];
struct SAM
{
    struct Node
    {
        int son[26];
        int ff,len;
    }t[MAX<<1];
    int last,tot;
    void init(){last=tot=1;}
    void extend(int c)
    {
        int p=last,np=++tot;last=np;
        t[np].len=t[p].len+1;
        while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
        if(!p)t[np].ff=1;
        else
        {
            int q=t[p].son[c];
            if(t[q].len==t[p].len+1)t[np].ff=q;
            else
            {
                int nq=++tot;
                t[nq]=t[q];t[nq].len=t[p].len+1;
                t[np].ff=t[q].ff=nq;
                while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
            }
        }
    }
}SAM;
char ch[MAX];
struct SegMentTree
{
    struct Node{int v;}t[MAX<<2];
    void Build(int now,int l,int r)
    {
        t[now].v=1e9;if(l==r)return;
        int mid=(l+r)>>1;
        Build(lson,l,mid);Build(rson,mid+1,r);
    }
    void puttag(int now,int w){t[now].v=min(t[now].v,w);}
    void pushdown(int now)
    {
        if(t[now].v==1e9)return;
        puttag(lson,t[now].v);puttag(rson,t[now].v);
        t[now].v=1e9;
    }
    void Modify(int now,int l,int r,int L,int R,int w)
    {
        if(L>R)return;
        if(L<=l&&r<=R){puttag(now,w);return;}
        pushdown(now);int mid=(l+r)>>1;
        if(L<=mid)Modify(lson,l,mid,L,R,w);
        if(R>mid)Modify(rson,mid+1,r,L,R,w);
    }
    int Query(int now,int l,int r,int p)
    {
        if(l==r)return t[now].v;
        pushdown(now);int mid=(l+r)>>1;
        if(p<=mid)return Query(lson,l,mid,p);
        else return Query(rson,mid+1,r,p);
    }
}A,B;
int main()
{
    SAM.init();
    scanf("%s",ch+1);n=strlen(ch+1);
    for(int i=1;i<=n;++i)SAM.extend(ch[i]-97);
    for(int i=1;i<=SAM.tot;++i)vis[SAM.t[i].ff]=true;
    A.Build(1,1,n);B.Build(1,1,n);
    for(int i=1;i<=SAM.tot;++i)
        if(!vis[i])
        {
            int l=SAM.t[i].len-SAM.t[SAM.t[i].ff].len,r=SAM.t[i].len;
            A.Modify(1,1,n,l,r,r-l+1);
            B.Modify(1,1,n,1,l-1,r+1);
        }
    for(int i=1;i<=n;++i)
        printf("%d\n",min(A.Query(1,1,n,i),B.Query(1,1,n,i)-i));
    return 0;
}

以上是关于BZOJ1396识别子串&BZOJ2865字符串识别(后缀自动机)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1396&2865 识别子串 后缀自动机 + 线段树

bzoj1396 识别子串

bzoj1396 识别子串

bzoj1396 识别子串

BZOJ 1396:识别子串 SA+树状数组+单调队列

bzoj1396: 识别子串