zoukankan      html  css  js  c++  java
  • bzoj1396 识别子串

    题目描述

    题解:

    好神啊

    建出后缀自动机,然后处理每个点parent树子树中endpos的数量,若为1即可成为识别子串。

    对于每个点维护原串所在位置以及right的最小值mn。

    然后套上线段树维护区间最小值。

    基本就这样了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 100050
    char s[N];
    struct Point
    {
        int len,pre,trs[28],pla;
    }p[2*N];
    int hed[2*N],cnt,n;
    struct EG
    {
        int to,nxt;
    }e[2*N];
    void ae(int f,int t)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        hed[f] = cnt;
    }
    int mn[2*N],siz[2*N];
    struct SAM
    {
        int tot,las;
        SAM(){tot=las=1;}
        void insert(int c)
        {
            int np,nq,lp,lq;
            np=++tot;
            siz[np] = 1;
            p[np].len = p[las].len + 1;
            p[np].pla = p[las].pla + 1;
            for(lp = las;lp&&!p[lp].trs[c];lp=p[lp].pre)
                p[lp].trs[c] = np;
            if(!lp)p[np].pre = 1;
            else
            {
                lq = p[lp].trs[c];
                if(p[lq].len == p[lp].len+1)p[np].pre = lq;
                else
                {
                    nq = ++tot;
                    p[nq] = p[lq];
                    p[nq].len = p[lp].len+1;
                    p[lq].pre = p[np].pre = nq;
                    while(p[lp].trs[c]==lq)
                    {
                        p[lp].trs[c] = nq;
                        lp = p[lp].pre;
                    }
                }
            }
            las = np;
        }
        void dfs(int u){for(int j=hed[u];j;j=e[j].nxt)dfs(e[j].to),siz[u]+=siz[e[j].to];}
        void build()
        {
            for(int i=2;i<=tot;i++)
            {
                mn[i] = p[p[i].pre].len+1;
                ae(p[i].pre,i);
            }
            dfs(1);
        }
    }sam;
    int ans[N];
    struct segtree
    {
        int v[N<<2];
        void pushdown(int u)
        {
            v[u<<1]=min(v[u<<1],v[u]);
            v[u<<1|1]=min(v[u<<1|1],v[u]);
        }
        void build(int u,int l,int r)
        {
            v[u]=n;
            if(l==r)return ;
            int mid = (l+r)>>1;
            build(u<<1,l,mid);
            build(u<<1|1,mid+1,r);
        }
        void insert(int u,int l,int r,int ql,int qr,int d)
        {
            if(l==ql&&r==qr)
            {
                v[u] = min(v[u],d);
                return ;
            }
            pushdown(u);
            int mid = (l+r)>>1;
            if(qr<=mid)insert(u<<1,l,mid,ql,qr,d);
            else if(ql>mid)insert(u<<1|1,mid+1,r,ql,qr,d);
            else insert(u<<1,l,mid,ql,mid,d),insert(u<<1|1,mid+1,r,mid+1,qr,d);
        }
        void down(int u,int l,int r)
        {
            if(l==r)
            {
                ans[l]=v[u];
                return ;
            }
            pushdown(u);
            int mid = (l+r)>>1;
            down(u<<1,l,mid);
            down(u<<1|1,mid+1,r);
        }
    }tr;
    int main()
    {
        scanf("%s",s+1);
        n = strlen(s+1);
        for(int i=1;i<=n;i++)
            sam.insert(s[i]-'a'+1);
        sam.build();
        tr.build(1,1,n);
        for(int i=1;i<=sam.tot;i++)
        {
            if(siz[i]==1)
            {
                tr.insert(1,1,n,p[i].pla-mn[i]+1,p[i].pla,mn[i]);
            }
        }
        tr.down(1,1,n);
        for(int i=2;i<=n;i++)ans[i] = min(ans[i],ans[i-1]+1);
        for(int i=n-1;i>=1;i--)ans[i] = min(ans[i],ans[i+1]+1);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    没时间写文章::>_<::
    使 iis 支持 flv 视频播放
    CentOS7系统配置国内yum源(阿里云)
    android adb启动失败问题 adb server is out of date. killing... ADB server didn't ACK * failed to start daemon *
    android开发 获取手机分辨率大小
    c++流操作>rdbuf()
    ROR:Mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost'
    android map如何获得Google Map API key
    Android有效解决加载大图片时内存溢出的问题
    Android开发之Intent跳转到系统应用中的拨号界面、联系人界面、短信界面
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10104201.html
Copyright © 2011-2022 走看看