后缀数组的第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: ...
随机推荐
- clone内容包含select2
如果克隆的内容包含select2,克隆之后要先删除select之后自动生成的span,再对select2进行初始化,生成新的元素.
- redis设置防火墙的问题
Linux 下载安装配置Redis完整步骤 安装: 1.获取redis资源 wget http://download.redis.io/releases/redis-4.0.8.tar.gz 2. ...
- dom 事件主要内容
一 . onclick(单击) 原图 单击btn1 在点击btn2 二 . onfocus 和 onblur onfocus(聚焦, 鼠标点击输入框) onblur(模糊, 鼠标点击输入框外的地方) ...
- github---无命令可视化界面操作
最近工作需要,研究了一下git,这个东西挺实用,给我的感觉并不是那么简单使用,我认为还可以再深入的研究一下,挺好玩的~ 说一下我的学习路线: 1.先看的廖老师的博客:https://www.liaox ...
- linux固定IP
在新安装的Linux系统命令行下, 敲入:ifconfig,显示如下界面. 上面这张图显示网卡没有启动,那么我们敲入代码:ifup eth0启动网卡. 网卡启动后,我们可以看出,IP地址和网关等其他信 ...
- codeforces24D
CF24D Broken robot 题目背景 小小迪带你吃瓜 题目描述 给出一个 n×m 的矩阵区域,一个机器人初始在第 x 行第 y 列,每一步机器人会等概率 的选择停在原地,左移一步,右移一步, ...
- 洛谷 P1441 砝码称重
题目描述 现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0). 输入输出格式 输入格式: 输入文件weight.in的第1行为有两个整数n ...
- 部署crm项目
准备工作 使用xftp将项目传到linux 将knight 传到linux上 将项目的数据导出 mysqldum -uroot -p --all-database > alldb.dump 在w ...
- puppet一个完整的实例
一个具体实例来简单说明puppet的具体结构 创建第一个配置 puppet的组成清单这主要包含这几个部分 资源,文件,模板,节点,类,定义 puppet中有个模块的定义,这个比较重要,基本是puppe ...
- 关于工具类中@Autowired注入为NULL的问题记录
记录:在实体类中加入@Component注解和@Autowired注解时Service不能注入成功. @Component //把普通pojo实例化到spring容器中 0 public clas ...