可持久/可回退化数据结构
可持久化数据结构用来解决这个问题:
1.在某个版本的基础上修改,同时生成新的版本
2.查询某个版本的值。
直接复制版本十分浪费。
为了查询以前的信息,可以不动以前的节点,只建新节点。
这就是可持久化数据结构的思想。
可回退化数据结构比上面的更弱。它用来解决这个问题:
1.在当前版本上进行修改
2.回退一步
这个数据结构的要求比普通数据结构更强,但是比可持久化数据结构更弱。
可以使用一个栈,存储被修改的位置,回退的时候再撤销。
但是很多时候,不能直接这么做。
比如可回退化单调栈,上面这么做时间复杂度是错的。
因为每次插入以后可能删除很多元素。
可以使用二分。由于栈中的元素是单调的,可以二分到需要弹栈的位置,然后把栈顶设为这个位置。
这样子时间复杂度就是正确的。
此外,上面两个数据结构都需要保证无论输入数据怎么样,操作时间复杂度都是一个较低的值val。
可持久化数据结构有这么一个转化:
如果把这个点向生成它的版本连边,则形成一颗树。
这棵树从某节点到根经过的操作就是这个版本经过的修改操作。
dfs整颗树,在到一个节点时插入,离开一个节点的时候删除。
则可持久化问题转化为更弱的可回退化问题。
例题:
可持久化数组
使用可持久化线段树维护
可持久化并查集(没做)
使用可持久化数组。
并查集要只加按秩合并,复杂度才正确。
可持久化平衡树(没做)
codechef WEASELSC
由于题目的楼梯可递增/递减,所以可以把楼梯翻转后再做一遍。
通过观察,我们可以发现这两个引理:
1.所有楼梯的高度都在a里出现过。
2.设li表示a里i左边第一个<ai的位置。
如果我们第i个位置选择了ai,则li+1到i都要选择ai。
这是因为如果不选择ai,结果不会更好。楼梯数不会更少
有了这两个引理,我们显然可以设dp方程。
设fk,i表示有k个阶梯,目前dp到i。
则fk,i=max
如果j<i且a_j<a_i,则把j作为i的父亲。
问题转化为:
有一颗树,每个节点有一条直线,求出某个点x到根的所有直线截x=k的最大值。
这是个经典的问题。可以通过从根建可持久化李超树/有根树点分治等方法解决。
集训队互测 unknown
一道论文题。可以看论文。
动态半平面交
七彩树(没做,上面一道题弱化版)
异或粽子
如果我们要求全局最大xor和,则可以trie树。
这是个trie树经典问题。
如果要求区间最大xor和,把它差分成前缀最大xor和。
可以可持久化trie树。
每次最多会修改log个节点。
如果要求k大xor和,则根据经典套路可以二分/堆。
取k次最大值,每次拓展出可能成为解的位置即可。
购票
[NOI2018]你的名字
bzoj二分图
简单线段树分治。
需要可回退化数据结构
bzoj城市建设
显然可以线段树分治。
但是线段树分治需要支持动态最小生成树,支持回退。
使用lct,连边把环上权值最小的边删除,回退cut即可。
codechef FBCHEF
https://www.cnblogs.com/ctmlpfs/p/13677219.html
CF757G
CF1037H
一道比较简单的字符串数据结构题。
题目要求字典序严格>询问串且最小。
可以使用一个简单的贪心。解一定是贪心的让构造的串匹配最长长度+一个严格>原串该位置的最小字符。
考虑求出构造的串匹配的最长长度。这是个基本的sam+线段树合并/sam+可持久化线段树+dfs序匹配问题。
我们要知道是否有p\in [l,r]且p-len+1\in [l,r]其中len=匹配的长度。
合起来就是p\in [l+len-1,r]
设nxt_i表示i节点后的最小字符。没有设为-1
nxt_i可以通过求出构造的串匹配的最长长度的方法求出。
枚举lcp即可得到答案/判定无解。
CF464E(没做)
[IOI2015]分组(忘了)
HNOI2019 JOJO(忘了)
loj3225(没做)
jzoj4611(没做)
loj 网格图
jzoj5750
CF1063F
挖掘性质:
引理1:如果我们倒过来选,显然每次选比上次长度+1的最优。
如果不是这么选,则找到从字符串长度小到大第一个不符合这个条件的串。
然后通过从这个串的首/尾删除/插入字符。把这个串的长度变成上一个串的长度+1。
容易发现这样子依然合法。
设f_i表示i作为开头最多能选几个。
如果我们枚举一个长度md,表示现在的f_i。
则要求对于[i+md,n]的区间存在一个j使得lcp(i,j)>=md-1且lcp(i+1,j)>=md-1
引理2:md可以二分。即如果存在以i为结尾的长度为md的解,也存在i为结尾的长度为md-1的解。
我们可以把所有解中,存在对应dp_i的最后一位的位的串拿掉,再删除重复的串的最上面一个。
容易知道,最上面的一个在原来如果长度为le+1,则重复的串的最下面一个长度为le。
且最上面的一个重复串存在对应dp_i的最后一位的位。
所以可以删除。
所以可以二分md
然而数据范围达到了5e5,这样子肯定是不可取的。
引理3:f_i-1<=f_{i+1}
如果把现在f_i的首位字符删除,则可以使用类似引理2的方法证明答案最多会小1。
移项得到f_i<=f_{i+1}+1
所以我们可以先把f_i=f_{i+1}+1,然后不断令f_i--,判定是否满足要求。
我们要求对于[i+md,n]的区间存在一个j使得lcp(i,j)>=md-1且lcp(i+1,j)>=md-1。
由于第一个条件的区间终点是n,所以可以倒着建可持久化线段树。
第二/三个条件,满足条件的肯定在后缀数组上是连续的一段,可以二分+st表求出。
查询这两个区间最大值是否>=md-1即可。
时间复杂度n\log_2n
loj6198
比较简单的字符串数据结构题。
有两种做法:
1.sa。
根据经典结论,两个字符串的lcp等于它在sa上的rmq。
考虑分治。每次取出最值分治。
这样子好处在于lcp是一定的。
接下来我们要求一个串对一个区间串的xor和的最大值。
这是个经典的问题。可以trie树解决。
但是直接分治时间复杂度是错误的。根据套路可以使用较小的xor较大的区间贡献答案。
根据启发式合并/轻重链剖分的复杂度,这样子时间复杂度是正确的
2.sam
根据经典结论,两个字符串的lcp等于它在sam parent树上的lca深度。
建立反串的sam。
dfs parent树。
我们要统计两个trie树的贡献。
这可以对trie树进行dfs。
当dfs到某个节点x时,枚举当前节点的第一个trie树选什么,根据大小关系得知它和哪个节点xor。
做完后把trie树合并到根即可。
(其实线段树分治,回滚莫队都需要可回退化数据结构,并且要求时间复杂度严格正确)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥