题解 【SR2.7-T5】【八云蓝自动机Ⅱ】
因为要求的是固定右端点为
那么显然只有当前枚举到的位置是三操作时,才会对答案产生影响
不难求出
-
如果
j 操作是操作一,那么对于l \le j ,答案增加了k ,对于l > j ,答案增加了a_x -
如果
j 操作是操作二,那么对于l \le j ,对答案的影响等价于在执行j 操作前,进行3 y操作产生的影响,对于l > j ,答案增加了a_x
显然 1 是容易处理的,而对于 2,我们将这个操作的影响转化为了一次区间加,和执行另一次操作的影响,依据这种分解关系,我们可以建立出一颗操作树,从儿子
这样的一些操作原本是不存在的,但是我们只会在二操作前查询这次操作对应的
为了方便一点,我们可以在操作一执行后也建立一个节点,这样 1 情况也可以转化为 2 情况
现在的题意是这样的:给你一个操作森林,每个节点上写着一个区间
现在要支持执行一个点到根路径上所有点的操作(称为“修改”),以及查询这个序列的一个区间之和(称为“查询”)
乍一看这个东西完全不可做,但实际上这个森林具有性质:
-
每个点往根走,经过的
[l,r] 区间彼此不相交,且后经过的区间永远在先经过的左边 -
三操作建立出的节点没有孩子,二操作建立出的节点至多有一个二操作的孩子
性质一意味着,一次修改对一次查询的贡献,我们是可以快速计算的,首先
由于性质一,所有与
而性质二意味着,我们对于这颗树进行重链剖分,从
设想一下,如果所有查询在所有修改后,该怎么做?dfs 这颗树,计算每个点被执行的次数,然后差分进行区间加,最后算一遍前缀和
这实际上意味着,我们可以在
而我们又可以快速计算一次修改对一次查询的贡献,于是做法已经呼之欲出了:定期重构,或者叫对时间轴分块
我们每
但计算一次修改对一次查询的贡献时,有一个问题是如何确定
一个 naive 的做法是倍增,最终复杂度大概是
比较正确的做法是,树剖,每条链上对于每个节点
考虑个简单的做法,直接对树进行 dfs,然后动态对每个节点,维护其到根路径上,每个位置所属的节点,类似 K 级祖先那个离线的
但相信没有人愿意写可持久化分块,也相信开不下空间,于是我们二次离线,然后枚举修改给查询加贡献
综上,如果视
-
一些拓展
本题本质上的查询只有两个变量,所以能否用莫队解决?
右端点
\pm 1 可以在操作树上计算贡献,而左端点\pm 1 的贡献则类似于作业 I 的问题,也就是你要动态维护f(l,r) 的值,区别在于一操作变为了区间修改,我只知道一个莫队的n \sqrt n \log n 做法或者说,能否不使用定期重构,而是进行树分块类似的操作?我们在进行树剖后,对每条链再进行分块,修改时,散块实现一个
O(1) - O(\sqrt n) 的分块,直接对答案数组进行修改,完整块打标记;查询时,先从答案数组算一下结果,再对于每个完整块结算贡献,这似乎是一个可行的思路希望赛后有人能给出其他做法,例如上面两种的具体实现
实际上就是出题人懒得想了,反正 std 做法看起来挺简单的(我本来打算加个
a_x 修改为a_y 的操作,破坏性质二的,但是我懒得搞了)