zoukankan      html  css  js  c++  java
  • 后缀数组模板第一版

    /*---------------倍增算法+RMQ后缀数组模板--------------
    
    输入:从0开始的字符串g,长度len最大为10^6
    输出:
     sa[]表示:n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺
     次放入 sa 中,sa[i]表示排第i位的字符串开头是sa[i],因为添加了一个结尾0,所以sa[0]=len
     height 数组(h[]):定义 h[i]=suffix(sa[i-1])和 suffix(sa[i])的最长公
     共前缀,也就是排名相邻的两个后缀的最长公共前缀。
     mrank[i]表示:以i位开头的字符串,排名为mrank[i]。mrank[len]=0;
     cal(x,y):查询g[b]g[b+1]...g[len-1]与g[d]g[d+1]...g[len-1]的最大前缀数。
    复杂度:空间复杂度33*len,时间复杂度,建立后缀数组为len*log(len),若不需要建立RMQ为len
     
    --------------------------------------------------*/
    
    
    int r[N];
    int sa[N];
    int scnt[N];
    int wa[N],wb[N],wv[N];
    int mrank[N];
    int h[N],th[N];
    int rmqdp[N][22];
    int savek[N];
     
    int cmp(int gg[],int a,int b,int k)
    {
        return gg[a]==gg[b] && gg[a+k]==gg[b+k];
    }
     
    void getsa(int str[],int sa[],int n,int m)
    {
        int i,*x,*y,*t;
        x=wa; y=wb;
        memset(scnt,0,sizeof(scnt));
        for(i=0;i<n;i++)
                scnt[ x[i]=str[i] ]++;
        for(i=1;i<m;i++)
                scnt[i]+=scnt[i-1];
        for(i=0;i<n;i++)
                sa[ --scnt[ str[i] ] ]=i;
     
        for(int p=1,j=1;p<n;j*=2,m=p)
        {
            for(p=0,i=n-j;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if( sa[i]>=j ) y[p++]=sa[i]-j;
            for(i=0;i<n;i++) wv[i]=x[ y[i] ];
            memset(scnt,0,sizeof(scnt));
            for(i=0;i<n;i++) scnt[ wv[i] ]++;
            for(i=1;i<m;i++) scnt[i]+=scnt[i-1];
            for(i=n-1;i>=0;i--) sa[ --scnt[ wv[i] ] ] = y[i];
            for(p=1,t=x,x=y,y=t,x[sa[0]]=0,i=1;i<n;i++)
                x[ sa[i] ] = cmp(y,sa[i],sa[i-1],j)?p-1:p++;
        }
    }
     
    void geth(int str[],int n)
    {
        h[n-1]=0;
        int p=0;
        for(int i=0;i<n-1;i++)
        {
            int tmp=mrank[i];
            while( str[i+p] == str[ sa[tmp-1]+p ] ) p++;
            h[i]=p;
            p--;
            p=max(0,p);
        }
    }
     
    void buildst(int n)
    {
        for(int i=1;i<=n;i++)
            rmqdp[i][0] = th[i];
        for(int i=1;(1<<i)<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if( j+(1<<(i-1)) >n ) rmqdp[j][i]=rmqdp[j][i-1];
                else rmqdp[j][i]=min(rmqdp[j][i-1],rmqdp[j+(1<<(i-1))][i-1]);
            }
        }
    }
    
    
    int cal(int x,int y)
    {
            x=mrank[x]; y=mrank[y];
            if(x>y) swap(x,y);
            x++;
            //然后就是求x到y的最小值
            int k = savek[y-x+1];
            return min(rmqdp[x][k],rmqdp[y-(1<<k)+1][k]);
    }
    
    void SuffixInit(char gg[],int len)
    {
        //初始化RMQ中得k
        for(int i=1;i<N;i++)
            savek[i] = floor( log((double)i)/log(2.0) );
        
        for(int i=0;i<len;i++)
            r[i]=gg[i];
        
        r[len++]=0;
        getsa(r,sa,len,300);
        for(int i=0;i<len;i++)
            mrank[ sa[i] ]=i;
        //for(int i=0;i<len;i++) printf("%s
    ",g+sa[i]);
        geth(r,len);
        for(int i=0;i<len-1;i++)
            th[ mrank[i] ]= h[i];
        buildst(len-1);
        
        /*
         int b,d;
         while(scanf("%d%d",&b,&d))
         {
            printf("%d
    ",cal( b,d ));//查询g[b]g[b+1]...g[len-1]与g[d]g[d+1]...g[len-1]的最大前缀数。
         }
         */
    }
    //求sa更快的3DC3 
    #define N 20020
    #define F(x) ((x)/3+((x)%3==1?0:tb))
    #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
    
    int wa[N],wb[N],wv[N],mws[N];
    char s[N];
    int str[3*N];
    int sa[3*N];
    int mrank[N];
    int h[N];
    int c0(int *r,int a,int b)
    {
        return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];
    }
    
    int c12(int k,int *r,int a,int b)
    {
        if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1);
        else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1];
    }
    
    void msort(int *r,int *a,int *b,int n,int m)
    {
        int i;
        for(i=0;i<n;i++) wv[i]=r[a[i]];
        for(i=0;i<m;i++) mws[i]=0;
        for(i=0;i<n;i++) mws[wv[i]]++;
        for(i=1;i<m;i++) mws[i]+=mws[i-1];
        for(i=n-1;i>=0;i--) b[--mws[wv[i]]]=a[i];
        return;
    }
    void dc3(int *r,int *sa,int n,int m)
    {
        int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
        r[n]=r[n+1]=0;
        for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i;
        msort(r+2,wa,wb,tbc,m);
        msort(r+1,wb,wa,tbc,m);
        msort(r,wa,wb,tbc,m);
        for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
        rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
        if(p<tbc) dc3(rn,san,tbc,p);
        else for(i=0;i<tbc;i++) san[rn[i]]=i;
        for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3;
        if(n%3==1) wb[ta++]=n-1;
        msort(r,wb,wa,ta,m);
        for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
        for(i=0,j=0,p=0;i<ta && j<tbc;p++)
        sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
        for(;i<ta;p++) sa[p]=wa[i++];
        for(;j<tbc;p++) sa[p]=wb[j++];
        return;
    }
    void geth(int str[],int n)
    {
        for(int i=0;i<n;i++)
            mrank[ sa[i] ]=i;
        h[n-1]=0;
        int p=0;
        for(int i=0;i<n-1;i++)
        {
            int tmp=mrank[i];
            while( str[i+p] == str[ sa[tmp-1]+p ] ) p++;
            h[i]=p;
            p--;
            p=max(0,p);
        }
    }
    int main()
    {
        while(scanf("%s",s))
        {
            int len=strlen(s);
            int n=0;
            for(int i=0;i<len;i++)
                str[n++]=s[i];
            str[n++]=0;
            dc3(str,sa,n,256);
            geth(str,n);
            //已经得到h
        }
        return 0;
    }
  • 相关阅读:
    牛客(14)链表中倒数第k个结点
    牛客(13)调整数组顺序使奇数位于偶数前面
    牛客(12)数值的整数次方
    牛客(11)二进制中1的个数
    牛客(10)矩形覆盖
    牛客(9)变态跳台阶
    牛客(8)跳台阶
    牛客(7)斐波那契数列
    Docker数据卷
    Docker镜像
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5093976.html
Copyright © 2011-2022 走看看