后缀数组
来源:互联网 发布:网络平台不收费标准 编辑:程序博客网 时间: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 ;}
阅读全文
0 0
- 后缀树/后缀数组
- 后缀树 后缀数组
- 【后缀数组】后缀排序
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 后缀数组
- 字符设备驱动高级篇3——自动创建字符设备驱动的设备文件
- php_lang_ref:Language Reference >> References Explained >> What References Are Not
- 文章标题
- Spring学习之Spring JDBC
- php_lang_ref:Language Reference >> References Explained >> What References Do
- 后缀数组
- php_lang_ref:Language Reference >> References Explained >> Passing by Reference
- 机器学习中的正则化处理
- Oracle-SQL命令复习总结_1
- Round 3 D
- 第一章面试题整理
- 字符设备驱动高级篇4——设备类(自动创建和删除设备文件的作用)相关代码分析
- 生成可重集的排列
- C++第四节课