后缀数组(O(n)三分实现)

比起WC关于后缀数组的倍增法,要更有效率,由于模版使用的是指针,所以在new和delete处效率会有所消耗

 

来自NIT的后缀数组模版 注意在字符串间加入特殊符号进行区分 避免LCP越界

 

SAMLPE测试为HDU 1403~~

 

 

#include < iostream >
#include
< cmath >
#include
< cstring >
using   namespace  std;
const   int  maxn = 210000 ;

char  s[maxn];
int  len,k;
int  sa[maxn],rank[maxn],lcp[maxn];
int  num[maxn];

inline 
bool  leq( int  a1,  int  a2,  int  b1,  int  b2)
{
    
return  (a1  <  b1  ||  a1  ==  b1  &&  a2  <=  b2);
}

inline 
bool  leq( int  a1,  int  a2,  int  a3,  int  b1,  int  b2,  int  b3)
{
    
return (a1  <  b1  ||  a1  ==  b1  &&  leq(a2, a3, b2, b3));
}

static   void  radixPass( int *  a,  int *  b,  int *  r,  int  n,  int  K)
{
    
int *  c  =   new   int [K  +   1 ];
    
int  i,sum;
    
for (i  =   0 ; i  <=  K; i ++
        c[i] 
=   0 ;
    
for (i  =   0 ; i  <  n; i ++
        c[r[a[i]]]
++ ;
    
for (i  =   0 , sum  =   0 ; i  <=  K; i ++ )
    {
        
int  t  =  c[i]; 
        c[i] 
=  sum; 
        sum 
+=  t;
    }
    
for (i  =   0 ; i  <  n; i ++
        b[c[r[a[i]]]
++ =  a[i];
    delete [] c;
}

void  suffixArray( int *  T,  int *  SA,  int  n,  int  K)
{
    
int  n0  =  (n  +   2 /   3 , n1  =  (n  +   1 /   3 , n2  =  n  /   3 , n02  =  n0  +  n2;
    
int *  R  =   new   int [n02  +   3 ]; R[n02]  =  R[n02 + 1 =  R[n02  +   2 =   0 ;
    
int *  SA12  =   new   int [n02  +   3 ]; SA12[n02]  =  SA12[n02  +   1 =  SA12[n02  +   2 =   0 ;
    
int *  R0  =   new   int [n0];
    
int *  SA0  =   new   int [n0];
    
int  i,j;
    
for (i  =   0 , j  =   0 ; i  <  n  +  (n0  -  n1); i ++ if (i  %   3   !=   0 ) R[j ++ =  i;
    radixPass(R , SA12, T 
+   2 , n02, K);
    radixPass(SA12, R , T 
+   1 , n02, K);
    radixPass(R , SA12, T , n02, K);
    
int  name  =   0 , c0  =   - 1 , c1  =   - 1 , c2  =   - 1 ;
    
for ( i  =   0 ; i  <  n02; i ++ )
    {
        
if (T[SA12[i]]  !=  c0  ||  T[SA12[i]  +   1 !=  c1  ||  T[SA12[i]  +   2 !=  c2)
        {
            name
++ ; c0  =  T[SA12[i]]; c1  =  T[SA12[i]  +   1 ]; c2  =  T[SA12[i]  +   2 ];
        }
        
if (SA12[i]  %   3   ==   1 ) { R[SA12[i]  /   3 =  name; }
        
else { R[SA12[i]  /   3   +  n0]  =  name; }
    }
    
if (name  <  n02)
    {
        suffixArray(R, SA12, n02, name);
        
for ( int  i  =   0 ; i  <  n02; i ++ ) R[SA12[i]]  =  i  +   1 ;
    }
    
else
        
for ( int  i  =   0 ; i  <  n02; i ++ ) SA12[R[i]  -   1 =  i;
    
for (i  =   0 , j  =   0 ; i  <  n02; i ++ if (SA12[i]  <  n0) R0[j ++ =   3   *  SA12[i];
    radixPass(R0, SA0, T, n0, K);
    
for ( int  p  =   0 , t  =  n0  -  n1, k  =   0 ; k  <  n; k ++ )
    {
        
#define  GetI() (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2)
        
int  i  =  GetI();
        
int  j  =  SA0[p];
        
if (SA12[t]  <  n0  ?
        leq(T[i], R[SA12[t] 
+  n0], T[j], R[j  /   3 ]) : leq(T[i],T[i  +   1 ],R[SA12[t]  -  n0  +   1 ], T[j],T[j  +   1 ],R[j  /   3   +  n0]))
        {
            SA[k] 
=  i; t ++ ;
            
if (t  ==  n02)
                
for (k ++ ; p  <  n0; p ++ , k ++ ) SA[k]  =  SA0[p];
        }
        
else {
            SA[k] 
=  j;
            
if ( ++ ==  n0) for (k ++ ; t  <  n02; t ++ , k ++ ) SA[k]  =  GetI();
        }
    }
    delete [] R; delete [] SA12; delete [] SA0; delete [] R0;
}

void  LCP( char   * str) 

    
int  i,j,k; 
    
for (k = i = 0 ;i < len;i ++
    { 
        
if ( rank[i]  ==  len  -   1  ) lcp[ rank[i] ]  =  k  =   0
        
else  
        { 
            
if ( k  >   0  )    k --
            j 
=  sa[ rank[i]  +   1 ]; 
            
for (;str[i + k]  ==  str[j + k];k ++ ); 
            lcp[rank[i]] 
=  k; 
        } 
    } 
}

int  main(){

    
int  i, n;

    scanf(
" %s " ,s);
    n
= strlen(s);
    s[n]
= ' A ' - 1 ;
    scanf(
" %s " ,s + n + 1 );
    len
= strlen(s);
    
for (i = 0 ;i < len;i ++ )
        num[i]
= s[i] - ' A ' + 1 ;
    suffixArray(num, sa, len, 
60 );
    
for (i = 0 ;i < len;i ++ )
        rank[sa[i]]
= i;

    LCP(s);

    
int  ans = 0 ;
    
for (i = 1 ;i < len;i ++ )
        
if (sa[i] < &&  sa[i - 1 ] > n   ||   sa[i] > &&  sa[i - 1 ] < n)
            
if (lcp[i - 1 ] > ans) ans = lcp[i - 1 ];

    printf(
" %d\n " ,ans);

    
return   0 ;
}

你可能感兴趣的:(后缀数组)