后缀数组模板/LCP模板

 1 //后缀数组模板,MANX为数组的大小
 2 //支持的操作有计算后缀数组(sa数组), 计算相邻两元素的最长公共前缀(height数组),使用get_height();
 3 //计算两个后缀a, 和b的最长公共前缀,请先使用lcp_init(),再调用get_lcp(a, b)得到
 4 //下面的n是输入字符串的长度+1(n = strlen(s) + 1), m是模板的范围 m=128表示在字母,数字范围内,可以扩大也可缩小
 5 //s[len] 是插入的一个比输入字符都要小的字符
 6 struct SufArray {
 7     char s[MAXN];
 8     int sa[MAXN], t[MAXN], t2[MAXN], c[MAXN], n, m;
 9     int rnk[MAXN], height[MAXN];//rnk和height数组
10     int mi[MAXN][20], idxK[MAXN];//用于计算LCP
11
12     void init() {
13         mem0(s);
14         mem0(height);
15     }
16     //读入字符串作为输入
17     void read_str() {
18         gets(s);
19         m = 128;
20         n = strlen(s);
21         s[n++] = ‘ ‘;
22     }
23     void build_sa() {
24         int *x = t, *y = t2;
25         rep (i, 0, m - 1) c[i] = 0;
26         rep (i, 0, n - 1) c[x[i] = s[i]] ++;
27         rep (i, 1, m - 1) c[i] += c[i - 1];
28         dec (i, n - 1, 0) sa[--c[x[i]]] = i;
29         for(int k = 1; k <= n; k <<= 1) {
30             int p = 0;
31             rep (i, n - k, n - 1) y[p++] = i;
32             rep (i, 0, n - 1) if(sa[i] >= k) y[p++] = sa[i] - k;
33             rep (i, 0, m - 1) c[i] = 0;
34             rep (i, 0, n - 1) c[x[y[i]]] ++;
35             rep (i, 0, m - 1) c[i] += c[i - 1];
36             dec (i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
37             swap(x, y);
38             p = 1;
39             x[sa[0]] = 0;
40             rep (i, 1, n - 1) {
41                 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
42             }
43             if(p >= n) break;
44             m = p;
45         }
46     }
47     void get_height() {
48         int k = 0;
49         rep (i, 0, n - 1) rnk[sa[i]] = i;
50         rep (i, 0, n - 1) {
51             if(k) k --;
52             int j = sa[rnk[i] - 1];
53             while(s[i + k] == s[j + k]) k ++;
54             height[rnk[i]] = k;
55         }
56     }
57     void rmq_init(int *a, int n) {
58         rep (i, 0, n - 1) mi[i][0] = a[i];
59         for(int j = 1; (1 << j) <= n; j ++) {
60             for(int i = 0; i + (1<<j) - 1 < n; i ++) {
61                 mi[i][j] = min(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]);
62             }
63         }
64         rep (len, 1, n) {
65             idxK[len] = 0;
66             while((1 << (idxK[len] + 1)) <= len) idxK[len] ++;
67         }
68     }
69     int rmq_min(int l, int r) {
70         int len = r - l + 1, k = idxK[len];
71         return min(mi[l][k], mi[r - (1 << k) + 1][k]);
72     }
73     void lcp_init() {
74         get_height();
75         rmq_init(height, n);
76     }
77     int get_lcp(int a, int b) {
78         if(a == b) return n - a - 1;
79         return rmq_min(min(rnk[a], rnk[b]) + 1, max(rnk[a], rnk[b]));
80     }
81     void solve() {
82     }
83 };
时间: 2024-08-25 06:05:43

后缀数组模板/LCP模板的相关文章

UVA11107 后缀数组(new模板)

IT 要走多久,要怎么走. IT 要走多久,要怎么走.这些问题,在我已经快毕业了一个年头的现在,又重新浮现在我的脑海里.一边是工作的了了模块,一边是可以自己无聊打发的时间.这不是我当初要的路,现在的路是一条没有激情,没有波澜,没有变革,没有无论是技术方向,还是职业规划此时此刻又都摆在了我的眼前.工作是工作,职业是职业. 我一直这么觉得,我不想把IT仅仅当为一种工作一样继续这样做下去,我不喜欢把IT当成一种生存计生这样的做下去.它应该是我的一种爱好,一种职业,一种诉求,一种偏执,一种倔强的追求.而

后缀数组详解+模板

后缀数组 注 SA[] 第几名是谁 后缀数组:后缀数组 SA 是一个一维数组, 它保存 1..n 的某个排列 SA[1] ,SA[2],……,SA[n],并且保证 Suffix(SA[i]) < Suffix(SA[i+1]),1≤i<n .也就是将 S 的 n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺次放入 SA 中. Rank[] 谁是第几名名次数组:名次数组 Rank[i]保存的是 Suffix(i)在所有后缀中从小到大排列的“名次 ” . r[]:原始数据j当前字符串的长度

[TJOI2017]DNA——后缀数组求LCP

题目大意: 给定一个文本串和一个模式串,求文本串中有多少个连续的子串和模式串相差不超过三个字符. 思路: 算是一道后缀数组的模板题. 直接做lcp,然后遇到匹配不上的就跳,跳的次数不能超过三次. 具体地,将两个字符串连在一起,中间加一个分隔符,然后求出height,用rmq维护height数组的区间最小值即可. /*======================================= * Author : ylsoi * Time : 2019.2.5 * Problem : luog

后缀数组-倍增算法模板

void build_sa(int m) { int *x = t, *y = t2; for(int i = 0; i < m; i ++) c[i] = 0; for(int i = 0; i < n; i ++) c[x[i]=s[i]] ++; for(int i = 1; i < m; i ++) c[i] += c[i-1]; for(int i = n-1; i >= 0; i --) sa[--c[x[i]]] = i; for(int k = 1; k <=

[TJOI2017]DNA --- 后缀数组

[TJOI2017]DNA 题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S, 有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状. 现在研究人员想知道这个基因在DNA链\(S_{0}\)上的位置. 所以你需要统计在一个表现出吃藕性状的人的DNA序列\(S_{0}\)上,有多少个子串可能是该基因, 即有多少个\(S_{0}\)的子串修改小于等于三个字母能够变成S. 输入输出格式 输入格式: 第一行

POJ2774 后缀数组

Long Long Message Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days: his mother is getting ill. Being worried about spending so much on railway tickets (Byterland is such a big

【后缀数组】【真难懂啊】

基本上一搜后缀数组网上的模板都是<后缀数组——处理字符串的有力工具>这一篇的注释,O(nlogn)的复杂度确实很强大,但对于初次接触(比如窝)的人来说理解起来也着实有些困难(比如窝就活活好了两天的光阴..),看了那么多材料感觉<挑战程序设计>的后缀数组解释理解起来会相对容易很多,然而它的复杂度是O(nlog2n)的,主要区别是对子串排序的时候前者用了基数排序--O(n),而后者用了快排--O(nlogn),这就导致了最终的复杂度后者比前者多了一个O(logn). 先整理下<挑

poj 2774 Long Long Message(后缀数组入门题)

1 /****************************************************************** 2 题目: Long Long Message(poj 2774) 3 链接: http://poj.org/problem?id=2774 4 题意: 给两个字符串,找最长的公共子串 5 算法: 后缀数组 6 算法思想: 后缀数组就是套模板求先应得数组,这题用到了两个数组,分 7 别是sa[],height[];sa[i]表示所有后缀按字典数排序后以s[i

后缀数组(Suffix Array)模板及简析——Part 1:构建SA和rank数组

后缀数组(Suffix Array,SA)是处理字符串的有力工具.它比后缀树更易实现,占用空间更少,并且同样可以解决千变万化的字符串问题 首先推荐罗穗骞的论文(网上搜一下就能搜到),里面对后缀数组的定义.实现和应用都做了详细的阐述 然而不幸的是罗神犇的代码简直魔性,蒟蒻表示这代码压的根本看不懂啊…… 所以在理解了后缀数组的构建过程之后,我重新写了一份模板代码.虽然啰嗦了点(代码比较大,而且变量名故意拉长了),不过相对比较好懂 而且论文中用到的辅助空间是4N,我的模板用了3N,事实上还可以优化到只