zoukankan      html  css  js  c++  java
  • bzoj1396识别子串(SAM+线段树)

    复习SAM板子啦!考前刷水有益身心健康当然这不是板子题/水题……

    很容易发现只在i位置出现的串一定是个前缀串。那么对答案的贡献分成两部分:一部分是len[x]-fa~len[x]的这部分贡献会是r-l+1;剩下一部分1~len-fa-1这部分会和i~r构成答案,写两棵线段树即可。

    然后就又是板子题了,两个板子(SAM+线段树)套起来。

    #include<bits/stdc++.h>
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    using namespace std;
    const int N=2e5+7,inf=0x3f3f3f3f;
    int n,lst=1,rt=1,cnt=1,ch[N][26],len[N],fa[N],sz[N];
    char s[N];
    struct tree{
        int mn[N<<2];
        void init(){memset(mn,0x3f,sizeof mn);}
        void pushdown(int rt)
        {
            if(mn[rt]==inf)return;
            mn[rt<<1]=min(mn[rt<<1],mn[rt]),mn[rt<<1|1]=min(mn[rt<<1|1],mn[rt]);
            mn[rt]=inf;
        }
        void update(int L,int R,int v,int l,int r,int rt)
        {
            if(L<=l&&r<=R){mn[rt]=min(mn[rt],v);return;}
            int mid=l+r>>1;pushdown(rt);
            if(L<=mid)update(L,R,v,lson);
            if(R>mid)update(L,R,v,rson);
        }
        int query(int k,int l,int r,int rt)
        {
            if(l==r)return mn[rt];
            int mid=l+r>>1;pushdown(rt);
            if(k<=mid)return query(k,lson);
            return query(k,rson);
        }
    }tr1,tr2;
    void build(int c)
    {
        int p=lst,np=++cnt;
        len[np]=len[p]+1,sz[np]=1;
        while(p&&!ch[p][c])ch[p][c]=np,p=fa[p];
        if(!p)fa[np]=rt;
        else{
            int q=ch[p][c];
            if(len[p]+1==len[q])fa[np]=q;
            else{
                int nq=++cnt;
                memcpy(ch[nq],ch[q],sizeof ch[q]);
                fa[nq]=fa[q],fa[np]=fa[q]=nq,len[nq]=len[p]+1;
                while(p&&ch[p][c]==q)ch[p][c]=nq,p=fa[p];
            }
        }
        lst=np;
    }
    int main()
    {
        scanf("%s",s+1),n=strlen(s+1);
        for(int i=1;i<=n;i++)build(s[i]-'a');
        for(int i=1;i<=cnt;i++)sz[i]=1;
        for(int i=1;i<=cnt;i++)sz[fa[i]]=0;
        tr1.init(),tr2.init();
        for(int i=1;i<=cnt;i++)
        if(sz[i]==1)
        {
            int l=len[i]-len[fa[i]],r=len[i];
            if(l>=2)tr1.update(1,l-1,r+1,1,n,1);
            tr2.update(l,r,r-l+1,1,n,1);
        }
        for(int i=1;i<=n;i++)printf("%d
    ",min(tr1.query(i,1,n,1)-i,tr2.query(i,1,n,1)));
    }
    View Code
  • 相关阅读:
    你能用多长时间停车?
    中国威胁论好像还挺严重的
    热爱生命
    lunix下shell脚本批量获取文件,批量修改文件内容
    sql数据操作的若干心得(二)向表中自动插入自增的ID
    Asp.net开发之旅动态产生控件
    Asp.net开发之旅GridView中嵌入DropDownList的一点心得
    Asp.net开发之旅开发环境
    Asp.net开发之旅简单的引用母版页
    Sql数据操作的若干心得
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10903108.html
Copyright © 2011-2022 走看看