后缀数组

来源:互联网 发布:网络平台不收费标准 编辑:程序博客网 时间:2024/05/17 21:39
参考 http://www.cnblogs.com/thmyl/p/6296648.html#_label0//后缀数组模板#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std ; const int maxn = 1e5 + 10 ;/* 后缀数组 倍增算法复杂度O(nlogn)sa下标代表第i大height代表第i大和第i-1大的lcprank下标代表第i个位置,rank[i] 代表以i起始的后缀的排名*/int sa[maxn] , rank[maxn] , height[maxn] ;void calheight( const char *r , int * sa , int n ){    int i , j , k = 0 ;    for(i = 1 ;i<=n ;i++)        rank[sa[i]] = i  ;    for(i = 0 ;i<n ;height[rank[i++]] = k)        for( k? k-- : 0 , j = sa[ rank[i] - 1] ; r[i+k] == r[j+k] ; k++) ;    for(int i = n ; i>= 1 ;i--)        ++sa[i] , rank[i] =rank[i-1] ;}int wa[maxn] , wb[maxn] , wv[maxn] , WS[maxn] ;int cmp( int * r , int a , int b , int l){    return r[a] == r[b] && r[a+l] == r[b+l] ;}//计算sa和height数组 void da( const char r[]  , int sa[] , int n , int m){    //n为字符串实际长度+1 , 因为在最后一位添加了0 , 保证后缀比较总能完成和有意义     int i , j , p , *x = wa , * y = wb , *t ;       //开始为j=1长度的第一个关键字的排序结果      //求每个后缀前缀一位的排名     for( i = 0 ; i< m ; i++) WS[i] = 0 ;    //基数排序 , x[i]代表第i个字符的大小,是一个数字     for( i = 0 ; i< n ;i++) WS[x[i] = r[i]] ++ ;    //累加wS , WS代表一个数字的排名     for( i = 1 ; i<m ; i++) WS[i] += WS[i-1] ;    //从后至前遍历,为了让相同字符靠后的位置排名更高     //i代表第i位置,x[i] 代表该位置的字符大小, --WS[x[i]] 代表x[i]字符的排名大小    //sa[ --WS[ x[i] ] ] = i 代表i(等号右边的i)位置字符x[i]的排名是 --WS[ x[i] ] ;     for( i = n-1 ; i>=0 ;i--)         sa[ --WS[ x[i] ] ] = i ;    cout<<"adsf"<<endl;     //倍增j , j长度的后缀前缀        for( j = 1 , p = 1 ;p< n ;j*=2 , m = p ){        //对第一个关键字排序的结果为sa        //对于x,去掉前j个字符,并且在后面补充j个0得到的字符串的相对位置就是第二个关键字的相对排序位置              for( p = 0 , i = n - j ;i< n ;i++)            //补充0的位置             y[ p++ ] = i ;        for( i = 0 ;i< n ;i++)            //去掉前j个字符得到的相对位置             if( sa[i] >= j )                 y[ p++ ] = sa[i] - j ;        // x[y[i]] 确定了一组新的字符串 wv,对wv基数排序就能得到2j长后缀前缀排名        // 下标y[i] 的排名为 --WS[ wv[i] ]         //则 sa[--Ws[wv[i]]]=y[i]        for( i = 0 ;i< n ;i++)            wv[i] = x[ y[i] ] ;        for( i = 0 ;i< m; i ++) WS[i] = 0 ;        for( i = 0 ;i< n ;i++) WS[ wv[i] ] ++ ;        for( i = 1 ;i< m ;i++) WS[i] += WS[i-1] ;        for( i = n -1 ; i >=0 ; i--)            sa[ --WS[wv[i] ] ] = y [i] ;        cout<<"fasdf"<<endl;        //更新x字符        for( t = x , x = y , y = t , p = 1 , x[sa[0]] = 0 , i = 1 ; i <n ;i++)            x[ sa[i] ] = cmp( y , sa[i-1] , sa[i] , j) ? p-1 : p++ ;    }        calheight( r , sa , n-1) ;}char str[maxn] ;int main(){    gets(str) ;    int len = strlen(str) ;    da( str , sa , len +1 , 130) ;    for(int i = 1 ; i<= len ;i++)        cout<<sa[i]<<" "<<height[i]<<endl;    return 0 ;}
//区间最值查询模板/*区间最值查询RMP  ST 算法 原理:  O(nlogn)预处理,O(1) 查询        预处理--使用动态规划,令F(i,j)表示以i起始的2^j长的子序列                F[i,0]即为原序列的每一个数,                有状态转移方程F(i, j ) = max(F(i,j-1), F(i+ (1<<(j-1)) , j-1 )        查询----对于i,j区间最值RMP(A,i,j)                 他的长度为 j-i+1                令k = log2( j - i + 1)                有i~j区间的最值max(F(i,k) , F[j- (1<<k) + 1 , k ) )复杂度  预处理 O(nlogn)        查询   O(1)应用    在线查询区间最值*/ #include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std ;const int maxn = 1e5 + 10 ;int F[maxn][20 + 1] ;void RMP(int n ){    //j代表区间长度1<<j     for ( int j = 1 ; j<= 20 ;j ++)        //i代表区间起点i        //区间[ i , i+ (1<<j) -1 ] 的最值为两部分区间[i , i + (1<<(j-1)) -1 ] 和[ i + (1<<(j-1)) , i + ( 1<<j) -1] 的最值         // F[i,j] = max( F[i , j-1] , F[i + (1<<(j-1)) +1 )          for(int i = 1 ; i <= n ;i ++)            //保证第二个子区间下标在区间范围内             if( i + ( 1<<(j-1)) <= n )                F[i ] [j]= max( F[i][j-1] , F[i + (1<<(j-1))] [ j -1] ) ; }int query(int i , int j ){    //划分区间长度让结果为两部分子区间的比较值    //取子区间为前1<<k个数和后1<<k个数     int k = log10( j - i + 1.0) / log10 (2.0) ;    return max( F[i][ k ] , F[j - ( 1<<k ) + 1] [ k]) ;}int main(){    //n代表序列长度,m代表询问个数     int n , m ;    cin>>n>>m ;    for(int i = 1 ;i <= n ; i ++){        cin>>F[i][0] ;    }    RMP( n ) ;    while(m--){        int i , j ;        cin>>i >> j ;        int ans = query( i , j) ;        cout<<ans<<endl;    }    return 0 ;}
原创粉丝点击