zoukankan      html  css  js  c++  java
  • 【BZOJ-1396&2865】识别子串&字符串识别 后缀自动机/后缀树组 + 线段树

    1396: 识别子串

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 312  Solved: 193
    [Submit][Status][Discuss]

    Description

    Input

    一行,一个由小写字母组成的字符串S,长度不超过10^5

    Output

    L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

    Sample Input

    agoodcookcooksgoodfood

    Sample Output

    1
    2
    3
    3
    2
    2
    3
    3
    2
    2
    3
    3
    2
    1
    2
    3
    3
    2
    1
    2
    3
    4

    HINT

    Source

    Solution

    BZOJ:1396

    这题使用 后缀自动机+线段树 的做法;

    首先按照这道题的要求,所有的识别子串一定是$|Right|=1$的节点所代表的子串之一,问题在于统计最短。

    这样可以考虑再记录每个$Right$集合的最后一个$endpos$,然后利用这个去考虑对原串每个位置的贡献。

    对于$[endpos-maxlen+1,endpos-minlen+1]$中的每个位置$x$,贡献就是$endpos-x+1$;

    理解起来就是对于$[endpos-maxlen+1,endpos-minlen+1]$中的每个子串都是单独存在的,所以这个$Right$集合贡献给他的答案就是这个点到$endpos$的长度。

    对于$[endpos-minlen,endpos]$中的每个位置$x$,贡献就是$minlen$;

    理解起来就是对于$[endpos-minlen,endpos]$中的每个子串显然是存在多个结束位置的,所以当前这个$Right$集合能够贡献给他的符合只出现一次且最短的,就是刚好跨过它的最小,即$minlen$。

    这样对于两种情况,分别用线段树去维护,至于第一种情况的$-x$是定值,所以拿到外面比较的时候再算进答案即可。

    BZOJ2865

    这道题和上道题完全一样,不过数据范围扩大了,需要卡内存...用上了map内存还是多10M...于是直接写 后缀树组+线段树 的做法了。

    和刚刚的想法类似。

    考虑固定左端点$l$,对后面的影响。

    容易发现,固定了$l$之后,对后面的答案,存在两种影响。

    设这样两种情况的分界点为$m$

    对于第一种影响$[l,m]$贡献的答案就是$lcp+1$,而第二种$[m+1,N]$的每个位置$x$贡献答案就是$x-l+1$

    所以这样可以枚举$sa_{i}$,对于$sa_{i}$它的$lcp+1$实际上就是与它相邻的两个后缀的$height_{max}+1$,那么分界点$m$恰好是$sa_{i}+lcp$.

    理解起来就是对于它的$lcp$显然是重复出现过的,那么这段的答案最短就是$lcp+1$,而对于这段之后的位置的影响,显然就是 那个位置到当前位置$sa_{i}$的距离长度的串 最短。

    用同样的方法用两棵线段树维护.

    Code

    BZOJ1396

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    #define MAXN 100010
    #define INF 0x7fffffff
    char S[MAXN];
    int N;
    namespace SegmentTree{
    #define lson now<<1
    #define rson now<<1|1
        struct SgtNode{
            int l,r,minn,tag;
        };
        struct SegmentTree{
            SgtNode tree[MAXN<<2];
            inline void Update(int now) {tree[now].minn=min(tree[lson].minn,tree[rson].minn);}
            inline void Build(int now,int l,int r)
            {
                tree[now].tag=tree[now].minn=INF;
                tree[now].l=l,tree[now].r=r;
                if (l==r) return;
                int mid=(l+r)>>1;
                Build(lson,l,mid); Build(rson,mid+1,r);
            }
            inline void Pushdown(int now)
            {
                if (tree[now].l==tree[now].r || tree[now].tag==INF) return;
                int val=tree[now].tag; 
                tree[now].tag=INF;
                tree[lson].minn=min(tree[lson].minn,val);
                tree[rson].minn=min(tree[rson].minn,val);
                tree[lson].tag=min(tree[lson].tag,val);
                tree[rson].tag=min(tree[rson].tag,val);
            }
            inline void Modify(int now,int L,int R,int val)
            {
                if (L>R) return;
                int l=tree[now].l,r=tree[now].r;
                Pushdown(now);
                if (L<=l && R>=r) {
                    tree[now].tag=min(tree[now].tag,val);
                    tree[now].minn=min(tree[now].minn,val);
                    return;
                }
                int mid=(l+r)>>1;
                if (L<=mid) Modify(lson,L,R,val);
                if (R>mid) Modify(rson,L,R,val);
                Update(now);
            }
            inline int Query(int now,int pos)
            {
                int l=tree[now].l,r=tree[now].r;
                Pushdown(now);
                if (l==r) return tree[now].minn;
                int mid=(l+r)>>1;
                if (pos<=mid) return Query(lson,pos);
                    else return Query(rson,pos);
            }
        }t1,t2;
    }using namespace SegmentTree;
     
    namespace SAM{
        int son[MAXN<<1][27],len[MAXN<<1],par[MAXN<<1],endpos[MAXN<<1],size[MAXN<<1];
        int last,root,sz;
        inline void init() {last=root=++sz;}
        inline void Extend(int c,int pos)
        {
            int cur=++sz,p=last;
            len[cur]=len[p]+1; endpos[cur]=pos; size[cur]=1;
            while (p && !son[p][c]) son[p][c]=cur,p=par[p];
            if (!p) par[cur]=root;
            else {
                int q=son[p][c];
                if (len[p]+1==len[q]) par[cur]=q;
                else {
                    int nq=++sz;
                    memcpy(son[nq],son[q],sizeof(son[nq]));
                    len[nq]=len[p]+1; par[nq]=par[q];
                    while (p && son[p][c]==q) son[p][c]=nq,p=par[p];
                    par[q]=par[cur]=nq;     
                }
            }
            last=cur;
        }
        inline void Build() {init(); for (int i=1; i<=N; i++) Extend(S[i]-'a'+1,i);}
        int st[MAXN],id[MAXN<<1];
        inline void Prework()
        {
            for (int i=1; i<=sz; i++) st[len[i]]++;
            for (int i=1; i<=N; i++) st[i]+=st[i-1];
            for (int i=1; i<=sz; i++) id[st[len[i]]--]=i;
            for (int i=sz; i>=1; i--) {
                int x=id[i];
                size[par[x]]+=size[x];
                endpos[par[x]]=max(endpos[par[x]],endpos[x]);
            }
        }
        inline void Work()
        {
            for (int i=1; i<=sz; i++)
                if (size[i]==1) {
                    int maxlen=len[i],minlen=len[par[i]]+1,end=endpos[i];
    //              printf("%d  %d  %d
    ",end,maxlen,minlen);
                    t1.Modify(1,end-maxlen+1,end-minlen+1,end+1);
                    t2.Modify(1,end-minlen+1,end,minlen);
                }
                 
            for (int i=1; i<=N; i++) {
                int x=t1.Query(1,i)-i,y=t2.Query(1,i);
                printf("%d
    ",min(x,y));
            }
        }
    }using namespace SAM;
    int main()
    {
        scanf("%s",S+1); N=strlen(S+1);
         
        t1.Build(1,1,N),t2.Build(1,1,N);
         
        SAM::Build();
        SAM::Prework();
        SAM::Work();
         
        return 0;
    }
    

    BZOJ2865

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define MAXN 500010
    char S[MAXN];
    int N;
    #define INF 0x3fffffff 
    namespace SegmentTree{
    #define lson now<<1
    #define rson now<<1|1
        struct SgtNode{
            int l,r,minn,tag;
        };
        struct SegmentTree{
            SgtNode tree[MAXN<<2];
            inline void Update(int now) {tree[now].minn=min(tree[lson].minn,tree[rson].minn);}
            inline void Build(int now,int l,int r)
            {
                tree[now].tag=tree[now].minn=INF;
                tree[now].l=l,tree[now].r=r;
                if (l==r) return;
                int mid=(l+r)>>1;
                Build(lson,l,mid); Build(rson,mid+1,r);
            }
            inline void Pushdown(int now)
            {
                if (tree[now].l==tree[now].r || tree[now].tag==INF) return;
                int val=tree[now].tag; 
                tree[now].tag=INF;
                tree[lson].minn=min(tree[lson].minn,val);
                tree[rson].minn=min(tree[rson].minn,val);
                tree[lson].tag=min(tree[lson].tag,val);
                tree[rson].tag=min(tree[rson].tag,val);
            }
            inline void Modify(int now,int L,int R,int val)
            {
                if (L>R) return;
                int l=tree[now].l,r=tree[now].r;
                Pushdown(now);
                if (L<=l && R>=r) {
                    tree[now].tag=min(tree[now].tag,val);
                    tree[now].minn=min(tree[now].minn,val);
                    return;
                }
                int mid=(l+r)>>1;
                if (L<=mid) Modify(lson,L,R,val);
                if (R>mid) Modify(rson,L,R,val);
                Update(now);
            }
            inline int Query(int now,int pos)
            {
                int l=tree[now].l,r=tree[now].r;
                Pushdown(now);
                if (l==r) return tree[now].minn;
                int mid=(l+r)>>1;
                if (pos<=mid) return Query(lson,pos);
                    else return Query(rson,pos);
            }
        }t1,t2;
    }using namespace SegmentTree;
     
    namespace SA{
        int r[MAXN],sa[MAXN],rank[MAXN],height[MAXN],st[MAXN],tx[MAXN],ty[MAXN];
        inline void Sort(int *x,int *y,int *sa,int L,int M)
        {
            for (int i=0; i<=M; i++) st[i]=0;
            for (int i=0; i<L; i++) st[x[y[i]]]++;
            for (int i=1; i<=M; i++) st[i]+=st[i-1];
            for (int i=L-1; i>=0; i--) sa[--st[x[y[i]]]]=y[i]; 
        }
        inline void DA(int *r,int *sa,int L,int M)
        {
            int *x=tx,*y=ty,*t,i,j,p;
            for (int i=0; i<L; i++) x[i]=r[i],y[i]=i;
            Sort(x,y,sa,L,M);
            for (j=1,p=1; j<L && p<L; j<<=1,M=p-1) {
                for (p=0,i=L-j; i<L; i++) y[p++]=i;
                for (i=0; i<=L; i++) if (sa[i]>=j) y[p++]=sa[i]-j;
                Sort(x,y,sa,L,M);
                for (t=x,x=y,y=t,x[sa[0]]=0,i=1,p=1; i<L; i++)
                    x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+j]==y[sa[i-1]+j]? p-1:p++;
            }
        }
        inline void Height(int *r,int *sa,int *rank,int *h,int L)
        {
            h[1]=0;
            for (int i=1; i<=L; i++) rank[sa[i]]=i;
            for (int i=1,j,k=0; i<=L; h[rank[i++]]=k)
                for (k? k--:k=0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);
        }
    }using namespace SA;
     
     
    int main()
    {
        scanf("%s",S+1); N=strlen(S+1);
        for (int i=1; i<=N; i++) r[i]=S[i]-'a'+1;
        SA::DA(r,sa,N+1,27);
        SA::Height(r,sa,rank,height,N);
         
    //  for (int i=1; i<=N; i++) printf("%d ",sa[i]); puts("");
    //  for (int i=1; i<=N; i++) printf("%d ",height[i]); puts("");
         
        t1.Build(1,1,N); t2.Build(1,1,N);
         
        for (int i=1; i<=N; i++) {
            int j=max(height[i],height[i+1])+1;
            if (j+sa[i]-1<=N) t1.Modify(1,sa[i],sa[i]+j-1,j);
            t2.Modify(1,sa[i]+j,N,1-sa[i]); 
    //      printf("%d    %d    %d    %d
    ",i,j,sa[i],j+sa[i]); 
        }
        for (int i=1; i<=N; i++) {
            int x=t1.Query(1,i),y=t2.Query(1,i)+i;
            printf("%d
    ",min(x,y));
        }
        return 0;
    }
    

    自己断断续续想了好久才想到...真的是弱的没救了....

  • 相关阅读:
    NSIS实现ArcEngine Runtime安装和自动注册
    .Net平台下开发中文语音应用程序(转载)
    NSIS:判断并安装.NET Framework的例子(转载)
    教你如何将IPHONE恢复正常(转载)
    C# SendMessage WPARAM大全 (收集)
    关于开发WPF的一些感想
    C#版本的CPU性能测试
    ITTC数据挖掘平台介绍(二) 微博数据挖掘和分析
    [XMOVE自主设计的体感方案] XMove 4.0 无线组网协议
    [XMOVE自主设计的体感方案] XMove 4.0节点介绍——抽象节点和硬件
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6284980.html
Copyright © 2011-2022 走看看