后缀数组的第X种求法
后缀自动机构造后缀数组。
因为有个SB题洛谷5115,它逼迫我学习后缀数组...(边分树合并是啥?)。
一些定义:sa[i]表示字典序排第i的后缀是从哪里开始的。Rank[i]表示后缀i的排名。height[i]表示排名i和i - 1的后缀的最长公共前缀。
首先我们可以建出后缀树,然后按字典序DFS即可获得sa数组和rank数组。
接下来要求height,使用经典后缀数组的求法即可。
说一下关于后缀数组经典倍增构造方法的一些理解。关于网上流传的那个锯齿形图,其实就是把上一次的两个排名拼接起来进行排序。
height数组的构建也很神奇。按照下标求,可以发现sa[Rank[i]](它自己)和j = sa[Rank[i] - 1]和i + 1的关系:
若i和j的[1, x]这些位相同,那么i + 1和j的[2, x]这些位相同。所以height[Rank[i]]至少有x - 1。
拍过的模板......暂时没找到模板题(板子字符集居然是62...是想卡爆SAM吧)
1 #include <bits/stdc++.h>
2
3 const int N = 200010;
4
5 int n, pw[N], ST[N][20];
6 int tr[N][26], len[N], fail[N], tot = 1, last = 1, ed[N], Lp[N];
7 int tr2[N][26], sa[N], Rank[N], height[N], num;
8 char str[N];
9
10 inline void insert(char c, int id) {
11 int f = c - 'a', p = last, np = ++tot;
12 last = np;
13 ed[np] = 1;
14 Lp[np] = id;
15 len[np] = len[p] + 1;
16 while(p && !tr[p][f]) {
17 tr[p][f] = np;
18 p = fail[p];
19 }
20 if(!p) {
21 fail[np] = 1;
22 }
23 else {
24 int Q = tr[p][f];
25 if(len[Q] == len[p] + 1) {
26 fail[np] = Q;
27 }
28 else {
29 int nQ = ++tot;
30 Lp[nQ] = Lp[Q];
31 len[nQ] = len[p] + 1;
32 fail[nQ] = fail[Q];
33 fail[Q] = fail[np] = nQ;
34 memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
35 while(tr[p][f] == Q) {
36 tr[p][f] = nQ;
37 p = fail[p];
38 }
39 }
40 }
41 return;
42 }
43
44 void DFS(int x) {
45 if(ed[x]) {
46 sa[++num] = Lp[x];
47 Rank[Lp[x]] = num;
48 }
49 for(int i = 0; i < 26; i++) {
50 if(!tr2[x][i]) continue;
51 DFS(tr2[x][i]);
52 }
53 return;
54 }
55
56 inline void getsa() {
57 for(int i = 2; i <= tot; i++) { /// build suffix tree
58 char c = str[Lp[i] + len[fail[i]]];
59 tr2[fail[i]][c - 'a'] = i;
60 }
61 DFS(1); /// DFS suffix tree to get SA and Rank
62 for(int i = 1, j, k = 0; i <= n; i++) { /// get height
63 j = sa[Rank[i] - 1];
64 if(!j) continue;
65 if(k) k--;
66 while(i + k <= n && j + k <= n && str[i + k] == str[j + k]) {
67 k++;
68 }
69 height[Rank[i]] = k;
70 }
71 return;
72 }
73
74 inline void prework() {
75 for(int i = 2; i <= n; i++) pw[i] = pw[i >> 1] + 1;
76 for(int i = 1; i <= n; i++) ST[i][0] = height[i];
77 for(int j = 1; j <= pw[n]; j++) {
78 for(int i = 1; i + (1 << j) - 1 <= n; i++) {
79 ST[i][j] = std::min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
80 }
81 }
82 return;
83 }
84
85 inline getSmall(int l, int r) {
86 if(l > r) std::swap(l, r);
87 l++;
88 int t = pw[r - l + 1];
89 return std::min(ST[l][t], ST[r - (1 << t) + 1][t]);
90 }
91
92 int main() {
93 scanf("%s", str + 1);
94 n = strlen(str + 1);
95 for(int i = n; i >= 1; i--) {
96 insert(str[i], i);
97 }
98 getsa();
99 prework();
100
101 int m;
102 scanf("%d", &m);
103 for(int i = 1; i <= m; i++) {
104 int x, y;
105 scanf("%d%d", &x, &y);
106 if(x == y) {
107 printf("%d ", n - x + 1);
108 }
109 else {
110 int t = getSmall(Rank[x], Rank[y]);
111 printf("%d ", t);
112 }
113 }
114
115 return 0;
116 }
SAM build SA求lcp
后缀数组的第X种求法的更多相关文章
- POJ 3261 Milk Patterns 后缀数组求 一个串种 最长可重复子串重复至少k次
Milk Patterns Description Farmer John has noticed that the quality of milk given by his cows varie ...
- 1402 后缀数组 (hash+二分)
描述 后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围.在本题中,我们希望使用快排.Hash与二分实现一个简单的 O(n log^2n ) 的后缀数组 ...
- CH 1402 - 后缀数组 - [字符串hash]
题目链接:传送门 描述 后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围. 在本题中,我们希望使用快排.Hash与二分实现一个简单的 $O(n \log ...
- CH1402 后缀数组【Hash】【字符串】【二分】
1402 后缀数组 0x10「基本数据结构」例题 描述 后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围.在本题中,我们希望使用快排.Hash与二分实现 ...
- 后缀数组:倍增法和DC3的简单理解
一些定义:设字符串S的长度为n,S[0~n-1]. 子串:设0<=i<=j<=n-1,那么由S的第i到第j个字符组成的串为它的子串S[i,j]. 后缀:设0<=i<=n- ...
- hdu 1403 Longest Common Substring(最长公共子字符串)(后缀数组)
http://acm.hdu.edu.cn/showproblem.php?pid=1403 Longest Common Substring Time Limit: 8000/4000 MS (Ja ...
- hdu3518 Boring counting(后缀数组)
Boring counting 题目传送门 解题思路 后缀数组.枚举每种长度,对于每个字符串,记录其最大起始位置和最小起始位置,比较是否重合. 代码如下 #include <bits/stdc+ ...
- 2019牛客多校第四场 I题 后缀自动机_后缀数组_求两个串de公共子串的种类数
目录 求若干个串的公共子串个数相关变形题 对一个串建后缀自动机,另一个串在上面跑同时计数 广义后缀自动机 后缀数组 其他:POJ 3415 求两个串长度至少为k的公共子串数量 @(牛客多校第四场 I题 ...
- 后缀数组SA学习笔记
什么是后缀数组 后缀数组\(sa[i]\)表示字符串中字典序排名为\(i\)的后缀位置 \(rk[i]\)表示字符串中第\(i\)个后缀的字典序排名 举个例子: ababa a b a b a rk: ...
随机推荐
- spring AOP源码分析(二)
现在,我们将对代理对象的生成过程进行分析. 在springAOP源码分析(一)的例子中,将会生成哪些对象呢? 可以看到将会生成六个对象,对应的beanName分别是: userDao:目标对象 log ...
- Django 2.11 静态页面404 解决
在settings中配置 STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR,"static"), ...
- groovy安装 ideal
参考:https://blog.csdn.net/newbie_907486852/article/details/80879745 (1) 首先下载groovy: https://gradle.or ...
- Yii2总结
1. Web访问流程(即在浏览器中输入一个网址至浏览器展现页面结果的过程) a. 将输入的网址提取出域名,在本地hosts文件中查找对应的IP地址(windows为C:/windows/system3 ...
- jQuery 操作Cookie
一个轻量级的cookie 插件,可以读取.写入.删除 cookie. 下载地址:http://plugins.jquery.com/cookie/ (在实际中可以用这个保存cookie保存用户的习惯, ...
- 【python练习题】程序15
#题目:利用条件运算符的嵌套来完成此题:学习成绩>=90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示. n = input('请输入成绩 :') n = int(n) if ...
- Modification Default Identity Table
Step 1. Open IdentityModel.cs to add following code. protected override void OnModelCreating(DbModel ...
- Python小练习
1.计算x的n次方 2.计算x的阶乘 3.计算1x1 + 2x2 + 3x3 ...+ NxN之和 def fun(n): s=0 while n > 0: s = s + n*n n = n ...
- 【XSY2786】Mythological VI 数学
题目描述 有\(1\sim n\)一共\(n\)个数.保证\(n\)为偶数. 你要把这\(2n\)个数两两配对,一共配成\(n\)对.每一对的权值是他们两个数的和. 你想要知道这\(n\)对里最大的权 ...
- 在ubuntu上安装运行ionic项目
1.安装nodejs.npm curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get install - ...