后缀数组

  1. #include <iostream>
  2. #include <string>
  3. #include <algorithm>
  4. using namespace std;
  5. #define Min(a,b) (a)<(b)?(a):(b)
  6. const int N = 2000;
  7. const int D = 10;
  8. const int M = 260;
  9. int n;
  10. char s[N] = "abcabdeabf";
  11. int cnt[N], mem[4][N], *rank, *nrank, *sa, *nsa, lcp[20][N];
  12. // lcp[i][j]: longest commen prefix ( suffix(sa[k+1]), suffix(sa[k]) ) j <= k < j+2^i
  13. void suffix()
  14. {
  15.  int i, j, k;
  16.  rank = mem[0];
  17.  nrank = mem[1];
  18.  sa = mem[2];
  19.  nsa = mem[3];
  20.  for(i = 0; i < n; i++) cnt[s[i]]++;
  21.  for(i = 1; i < M; i++) cnt[i] += cnt[i-1];
  22.  for(i = n-1; i >= 0; i--) sa[--cnt[s[i]]] = i;
  23.  for(rank[0]=0, i=1; i < n; i++)
  24.  {
  25.   rank[sa[i]] = rank[sa[i-1]];
  26.   if(s[sa[i]]!=s[sa[i-1]]) rank[sa[i]]++;
  27.  }
  28.  for(k = 1; k<n && rank[sa[n-1]] < n-1; k*=2)
  29.  {
  30.   for(i = 0; i < n; i++) cnt[rank[sa[i]]] = i+1;
  31.   for(i = n-1; i >= 0; i--) if(sa[i]-k>=0)
  32.    nsa[--cnt[rank[sa[i]-k]]] = sa[i]-k;
  33.   // max(sa[i]-k)=n-k-1 , therefore i = n-k;
  34.   for(i = n-k; i < n; i++)
  35.    nsa[--cnt[rank[i]]] = i;
  36.   for(nrank[nsa[0]], i=1; i < n; i++)
  37.   {
  38.    nrank[nsa[i]] = nrank[nsa[i-1]];
  39.    if(rank[nsa[i]] != rank[nsa[i-1]]
  40.     || rank[nsa[i]+k] != rank[nsa[i-1]+k])
  41.    nrank[nsa[i]]++;
  42.   }
  43.   swap(rank, nrank);
  44.   swap(sa, nsa);
  45.  }
  46. }
  47. void print()
  48. {
  49.  for(int i=0;i<n;i++) printf("%d %s/n", sa[i], s + sa[i]);puts("");
  50.  puts(s);for(int i=0;i<n;i++) printf("%d ", rank[i]);puts("");
  51. }
  52. void get_lcp_rmq()
  53. {
  54.  int i, j, k;
  55.  for(i=0,k=0; i<n; i++)
  56.  {
  57.   if(rank[i]==n-1) lcp[0][rank[i]]=k=0;
  58.   else
  59.   {
  60.    if(k>0)k--;
  61.    j = sa[rank[i]+1];
  62.    for(;s[i+k]==s[j+k];k++) ;
  63.    lcp[0][rank[i]]=k;
  64.   }
  65.  }
  66.  for(i=0,k=1; k<n; k*=2, i++)
  67.  {
  68.   for(j = 0; j+k < n; j++)
  69.    lcp[i+1][j] = Min(lcp[i][j], lcp[i][j+k]);
  70.  }
  71. }
  72. int rmq(int a, int b)
  73. {
  74.  int i, j, k;
  75.  if(a==b) return n-1-a;
  76.  a = rank[a];
  77.  b = rank[b];
  78.  if(a>b) swap(a,b);
  79.  int t=b-a;
  80.  for(i=0,k=1; 2*k<t; i++,k*=2) ;
  81.  return Min(lcp[i][a], lcp[i][b-k]); // not  b-k+1
  82.  // lcp[0][i]: LCP(i,i+1)
  83. }
  84. int main()
  85. {
  86.  int i, j, k;
  87.  n = strlen(s);
  88.  s[n++]=0;
  89.  memset(cnt, 0, sizeof(cnt));
  90.  memset(mem, 0, sizeof(mem));
  91.  suffix();
  92.  print();
  93.  get_lcp_rmq();
  94.  printf("%d/n", rmq(2,3));
  95.     return 0;
  96. }
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值