Problem Lists for data structures

Problem Lists for data structures

0x41 并查集

典型应用,维护具有传递性的关系。

“边带权”的并查集,用于维护更多集合里元素之间的信息,具体做法是假设每条边都有权值,这个权值在执行get时进行维护。

本题中,按照预期,你要维护的应该是这个战舰到头(root)的距离,所以在合并之时加上前面战舰的数量。

其实理论上讲,因为路径压缩的存在,除非没有执行get操作,否则在任何时刻一个元素都不会距离root超过1个节点(因为每次合并都连到根上)。这样一次一次累计下来,即使这个并查集一直是这种“菊花”形状,也保证答案是对的。

所以我们提出,“边带权”可以维护的信息一般要求是:与并查集的树形无关、易于在合并过程中维护

"扩展域"的并查集,用于维护元素的多个属性,具体做法是将元素的属性拆点,此时,如果两个元素的属性点在同一集合,我们就认为这两个点的该属性是等价的,这就意味着如果我说x满足a属性,而这点又和y属性的b代表点在一个集合,那么我们就知道y也满足b属性

在本题中,我们为了维护多种传递关系“同类的同类是我的同类”、“同类的天敌是我的天敌”、“天敌的天敌是我的食物”、“同类的食物是我的食物”、“天敌的同类是我的天敌”、“天敌的食物是我的同类”这些关系,所以为每个点扩展了3倍域(注意,以上描述其实是基于题目的特殊性“环形食物链”)

如果我们将x的天敌与y的天敌合并,这就意味着如果有某个点是x的天敌,那么他也是y的天敌,这就是上面“同类的天敌是我的天敌”这一条。

扩展域能够维护的信息,要是”无向的“,具体来说就是由命题”若P则Q“可以推导出否命题、逆否命题、逆命题。当然,满足以上要求,当然是有传递性的。

所以说,并查集在这里,其实就是维护了无向图的连通性,从x走到y,就像是从x命题推到y命题。

本题没别的,就是维护连通性,可是有删除操作。

我们使用转化法,倒序处理询问,将删除转化为添加。

0x42 树状数组

  • 树状数组区间修改区间查询 树状数组维护的一般性

推柿子,把求和公式里不和循环变量i相关的提出来,这样就可以实现用树状数组维护了。

差分转化无需多言。

这题提示我们,如果你需要维护某个代数式在区间上的值,那么如果这个代数式可以化为一种比较一般的形式:即求和中的项只与循环变量有关,那么可以考虑树状数组维护。

  • lost cow ACWing 244 树状数组倍增结合

这个问题采用树状数组只是作为工具,其核心是倍增/二分,这里着重探讨倍增。

这里采用的思想就是”以二进制划分为基础,能累计则累计“,其实你发现我们上面讨论的那个用树状数组求区间最大值的算法也是这个思想,只是由于要用树状数组这个框架,所以效率没那么高。其实最理想状态下二进制划分就该满足TG178X论证中的那个引理那么准确的形式:

「引自TG178X的blog」xN+,x=i=0ci2i\forall x\in \mathbb{N^+},x=\sum\limits^{\infty​}_{i=0}c_i​⋅2^i,其中ci0,1c_i​\in {0,1},所有 ci​ 构成的集合与之确定的 x 唯一互相对应。换句话说,任意一个正整数关于 2 的不重复次幂的分解是唯一的

但是这样,导致我们很难进行维护,物极必反,反而增添维护时间。

求逆序对,老经典了呢。不过,这个题需要转化:

火柴距离最小意味着就必须达到:大的对大的、小的对小的

设置一个索引q,令q[a[i]]=b[i](a[i],b[i]是原序列排序后该元素对应在原序列中的位置)

可以看出,其实以上转换的意义就是以a[i]为关键字对b[i]排序

随后发现,在已经排过序的目标状态中,q[a[i]]=a[i]

现在把q调整为合适顺序即计算逆序对。

0x43 线段树

其实有的lazy tag是有优先级的,而且有可能影响其他tag。

就比如这里,必须先处理mul标记。

转化矩形为区间操作,使用线段树进行维护。

细节挺多,我当时做的时候,调了一周,重构无数,才调出来~~(还发了条朋友圈,想想那时我多菜啊,捂脸)~~

这个确实难以看出线段树,因为这里并没有什么区间操作,甚至没有序列。

但是你发现,这么操作是不可能的,因为不取模你那个数会炸,然后你模了吧他又要求是对原数进行操作,所以最后只能重新全部计算。其实这个时候序列就已经诞生了。

但是注意到每个数只会除一次,而且除的是已经乘过的数,故就可以把它转化为序列操作,就只是带修改,然后求全局乘积,故选择线段树。

  • Interval GCD ACWing246 转化法

这题使用”更相减损术“,将原来不方便进行区间修改的GCD序列,转化为对差分序列的操作

使用线段树合并进行书上差分数组的合并。

0x44 分块

本题就是求区间众数,强制在线的算法。

分块维护块上各种蒲公英的数量,已经分成的整段从第L块到第R块的众数。

随后暴力扫描两边的部分,查看添加里面的蒲公英之后

所以说,这个题其实给我们这样的启示:

在思考一个比较不好维护的信息时如果考虑分块,那么就要考虑答案可能来自哪里,一般分为:块上、边上,然后考虑边上和块上对整体答案的贡献。如果此时发现,有些信息是块的一种属性,是对答案合成必须的,或者是静态的(例如此处块上的众数),那么可以先预处理出来,这样可以省时间。

这里就不放小Z的袜子了,虽然那个很经典。

但是如果莫队带修,阁下又该如何处理?

显然,莫队优化的关键就是分块排序,但是排了序之后在“操作时间”上操作序列就乱了,所以可能出现有的时候询问已经处理了可是修改还没有处理,那么我们只能强行处理,就是说如果修改的太多就改回去,没修改够就改回来,记录这次询问之前需要执行几次修改,如果没改够就循环执行。

0x45 点分治

学的其实不深,放个模板

现在来看,细节还是很多。不管是树上直接统计还是利用合法点对的单调性使用尺取法,思维核心即分治。

如果真的需要对树上路径进行静态统计,可以考虑使用淀粉质。

通常,这种问题“统计路径”都要转化为“统计路径端点”来实现。

0x46 平衡树

20180722220546910 (329×241) (csdn.net)

其实平衡树,最主要的就是作为工具,这里讨论一些他的典型用法。

相比于Treap,FHQ-Treap可以执行区间操作(它能按size分出序列,不过在这时,其实我们不是将序列的原数值作为关键码,而是相当于默认以数字下标做关键码,然后那个值只是存储的额外信息罢了),是更加通用的结构。这里着重讨论它。

要求对序列某区间进行翻转。

线段树行吗?不行,因为线段树的区间是二进制拼成的,你没办法把区间作为一个整体来交换。(不过似乎可以块状链表,这是一种更加平衡了改和查的链表结构)

那么就只能用平衡树,而且不能是有旋转Treap,要一个能分出区间的。

此时我们使用FHQ,然后将FHQ的根节点打上翻转标记,像线段树一样,在递归下去之前下传标记,交换两儿子。

这个题告诉我们,如果某一个操作必须把整个区间提取出来,那就用FHQ吧(好像还有一种叫Splay也可以)

这题本质上平衡树只是一种工具,重点是里面转换的方法。

对于这种题目,根据复杂度理论,判定难度小于求解,不妨先设答案,将限定条件转化为数学语言,然后观察代数式的性质,无论是对于要使用求解转判定还是什么都很有帮助。

这里我们发现,不便值的表达式在左边人数和和右边人数和相等时取到最小值,则问题化为求最中间那个人住的屋子,可用平衡树维护。(本题带修改)

本题的元素实际上是区间,我们重定义等于和小于号,然后选择在每次插入时删除相等元素,FHQ可以实现的经典操作。(只要再分裂一次,按照区间[1,l-1]即可)

0x47 离线分治

好吧五个月之后的今天我也是终于成功打出来一个CDQ,就是下面这个

这个题比较简单所以我才选这个切qwq,主要题意就是求区间和在[L,R]之间的区间个数。

转化为前缀和形式,就是Lsum(r)sum(l1)RL\leq sum(r)-sum(l-1)\leq R

化为L+sum(l1)sum(r)R+sum(l1)L+sum(l-1)\leq sum(r) \leq R+sum(l-1)

那么为了满足隐含条件LRL\leq R,我们选择用CDQ分治取消这一维限制,故在合并答案时先扫描右半部分加入树状数组,然后扫描左半部分累积答案。

注意离散化,有可能sum是负的。总共复杂度是O(Nlog2N)\operatorname O(N \log^2 N)

所以说,这个印证了我们上面的说明,那就是CDQ是用来降维的

当然,这个题就是求:在一个环形上,每次有区间加操作,对于每个区间,询问在第几次操作后会大于等于某个值。

环不好处理,直接破环成链。

当然可以用可持久化线段树+二分做,这是显然的。为每次操作制造一个副本。

现在我们考虑整体分治,根据以上描述,就是将答案域进行划分,如果我们在处理solve(k,l,r),即对l,r中的国家(已经排序)、前k个操作中再求解

唉,我还是别写了,放个我觉得帮助最大的题解:Link (by @ysy20021208)

这篇题解很好地解释了“为什么要用整体二分”、“整体二分跟二分有啥关系”、“整体二分应该怎么用”这几个问题,看完再类推一下,你应该就能学会整体二分。

0x48 可持久化数据结构

posted @ 2023-07-10 12:23  haozexu  阅读(10)  评论(0)    收藏  举报  来源