首页 > 其他分享 >当用 SA 来建后缀树

当用 SA 来建后缀树

时间:2023-04-08 16:46:46浏览次数:45  
标签:log 后缀 text Trie 来建 SA 节点

因为学不会什么串串技术,所以我只会 SA,至于 SAM 啥的我一窍不通,而后缀树也只知道定义!所以别和我说 Ukkonen 算法,因为我不会

以下假设原串 \(\text{S}\) 长度为 \(n\),我们在后缀数组 \(\text{SA}\) 开头插入一个空串,用 \(\text{H}\) 数组(好像通常叫做 \(\text{height}\) 数组?)表示 \(\text{SA}\) 上相邻两个串的 \(\operatorname{lcp}\) 长度;即 \(\text{SA}_0=\varnothing\),\(\text{H}_{k}=\operatorname{len}(\operatorname{lcp}(\text{SA}_{k-1},\text{SA}_{k}))\)。

建立 \(\text{SA}\) 的复杂度一般是 \(O(n\log n)\) 或者 \(\Theta(n)\) 的,建立 \(\text{H}\) 的复杂度一般是 \(\Theta(n)\) 的。我们以下就不妨认为该部分预处理的复杂度为 \(O(n\log n)\) 的。通常来说,只要 SA 部分的常数实现得足够好,该部分就不会成为瓶颈。


后缀树是由原串 \(\text{S}\) 的每个后缀串所组成的 Trie。容易发现其节点个数是 \(O(n^2)\) 的。

后缀树的特殊之处在于,其仅仅只用记录 \(\Theta(n)\) 个后缀的信息。

因此,我们其实并不用建出后缀树作为 Trie 的本身,而只用建出其对应的压缩 Trie 即可。

怎么办?

注意到压缩 Trie 其实就是由各个后缀所对应的节点构成的一颗虚树,我们只用建出这颗虚树即可!

容易发现,\(\text{SA}\) 本身的顺序就是这些后缀树上关键点按 dfn 序排列所得结果,而 \(\text{H}\) 数组标识着 \(\text{SA}\) 序上相邻两个关键点的 \(\text{lca}\) 深度。于是我们直接按 \(\text{SA}\) 序插入节点即可建出虚树。

这样我们就建出了一颗压缩后的后缀树。

如果想要每个关键节点都是叶子节点从而来简化讨论,我们通常可以在原串 \(\text{S}\) 的末尾添加一个特殊字符 \(\tt\$\),这样每个后缀都是互不包含的,并且 \(\operatorname{lcp}\) 大小不会发生改变。


例题 区间本质不同子串个数

我们先建出一颗后缀树。

对左端点从右往左作扫描线,每次加入一个后缀,也就是后缀树上一条到根的路径。

在后缀树上每个节点处记录上其最后一次被覆盖的时间 \(t_p\),以及其深度 \(d_p\)。

容易发现,在原本的 Trie 上,一个节点对某个 \(r\) 有贡献,当且仅当 \(t_p+d_p\le r\)。

在压缩 Trie 上,每条边标志的节点的 \(d_p\) 是一段连续的区间,而 \(t_p\) 与该边下部连接的节点相同。

于是我们就要支持若干次更改到根为止的 \(t\)。

考虑暴力维护各个颜色段对应的链顶,暴力切换,使用树剖 / GBT 来维护颜色。

然后使用 LCT 的均摊分析,可以证明颜色切换总次数是 \(O(n\log n)\) 级别的。

维护每个 \(t_p+d_p\) 有多少个,单次修改就是区间 \(\pm1\),单次询问就是前缀求和,拿个 BIT 做一下即可;如果要求强制在线,可以使用主席树维护。

总复杂度 \(O(n\log^2n+q\log n)\)。

代码咕了。


例题 「NOI2018」你的名字

我们离线下来,在修改串和询问串中间塞特殊字符,末尾塞一个特殊字符,建出一颗后缀树。

然后类似于刚刚的做法,对左端点扫描线,每次加入一个后缀。

查询的部分需要做一个容斥(计算原本的本质不同子串数目减去在 \(T_{l,r}\) 中出现的部分),并且还需要一个树上二分。

在 \(T_{l,r}\) 中出现的部分的贡献较为繁杂,因为一个二分出来的节点可能会在压缩 Trie 的一条边上出现,所以需要先去重,然后再计算该部分贡献,再扣除相邻两项的 \(\operatorname{lcp}\) 长度(显然 \(\operatorname{lcp}\) 必然只会在顶点处出现)。

我使用了全局平衡二叉树实现,总复杂度 \(O((n+q)\log n)\)。需要非常注意建后缀数组部分的常数

如果强制在线也能做,但是会难写很多。(每次得单独二分,不能直接预处理建出 \(\text{SA}\) 了)

代码实现

标签:log,后缀,text,Trie,来建,SA,节点
From: https://www.cnblogs.com/myee/p/when-building-SuffixTree-with-SuffixArray.html

相关文章

  • linux kernel 编译的过程中 make defconfig、 make menuconfig、 make savedefconfig
    原文:https://www.cnblogs.com/xingboy/p/16478998.html1、 makedefconfig首先通过makexxx_defconfig,生成最开始的.config,相当于把XXX_defconfig文件复制为.config文件,其中defconfig是最小的config项,kernel编译会根据.config文件去编译驱动情况,加载过改指令后,后......
  • SAP销售订单开票报错科目确定期间出错的原因分析及解决方案 ​
    在SAP/ERP系统日常运维中,可能会遇到类似如下这样问题:在创建销售发票时候,系统报错提示如下,错误消息号:VF051。针对上图问题,要找到这问题的原因,首先需要了解下销售收入相关科目确定的配置逻辑销售收入相关科目确定的配置事务码:VKOASAP系统收入相关科目确定逻辑在一般情况下收入相关科......
  • USACO2023
    Breakdown将过程逆序,即加边并维护以下信息——\(f_{k,i,j}\)表示从\(i\)到\(j\)恰走\(k\)步的最短路(其中\(k\in[0,2]\))\(fs_{k,i}\)表示从\(1\)到\(i\)恰走\(k\)步的最短路(其中\(k\in[0,4]\))\(ft_{k,i}\)表示从\(i\)到\(n\)恰走\(k\)步的最短路(其中\(k\in[0,4]\))任取\(p......
  • SAP报表修改-WBS销售订单汇总层报表
    1.问题描述给报表增加两行,1.1.1车间机械设备-自制设备,和1.1.2车间机械设备-外购设备2.问题解决2.1先在配置表加上两行列标题,事务代码SM30,输入配置表名称ZINT_CONIFIG点击新建“条目”添加,实际情况由于加了两行,序号要改动,所以将数据导出excel表格修改后再批量导入。2.2......
  • 2023 年值得关注的7个SaaS趋势
    软件即服务(SaaS)在过去十几年中逐渐走向主流,SaaS在越来越多的行业中取代本地部署系统,提供尖端的解决方案。SaaS产品之间也越来越卷,竞争加剧,客户的期望也越来越高。 PriceIntelligently最近发布的一项研究表明,2015年投放市场的SaaS产品平均有2.6个竞争对手。五年后,这个......
  • Mac Apple 芯片运行 Vue 项目中 node-sass 转为 sass 遇到的问题记录,node-sass 替换成
    背景:前段时间因为某些原因将window笔记本换成MacM1pro,然后运行项目的时候发现高于node12版本的项目中不支持node-sass。记录下解决相关问题之后的记录......
  • RSA
    RSA刷题Normal_RSA(详细)文件下载下来是这样的查阅信息发现:带有PEM文件扩展名的文件是用于私密传输电子邮件的隐私增强型邮件证书文件。PEM格式使用base64对二进制进行编码,以便它以ASCII字符串形式存在。PEM文件是Base64编码的证书。PEM证书通常用于web服务器,因为他们可以通......
  • salesforce学习笔记(3-1)- JavaScript Promise(LWC)
    在JS代码中,Promise到底有什么作用?首先,我们知道的是,Javascript是单线程的,什么意思呢?就是说JS在同一时间只能做一个操作,代码的执行是一行一行进行的:  这种执行方式带来的问题就是在我们打开某个画面的时候,画面可能会卡住转圈、加载中状态很久,用户体验感很差。Promise可用于......
  • 21An efficient message-authentication scheme based on edge computing for vehicul
    ......
  • P9019 [USACO23JAN] Tractor Paths P
    ProblemLuoguP9019[USACO23JAN]TractorPathsPSolution首先有一个显然的结论,区间\(i\)向右能到的区间是\([i+1,RT_i]\),向左能到的区间是\([LT_i,i-1]\)。根据这个考虑倍增。定义跳一步表示从当前区间去到最远能去的区间。设\(f_{i,j}\)表示区间\(i\)向右跳\(j\)......