最近听说 SDOI2017 R2 某题可以用我论文中的“基于链的分治优化树上动态 DP”的方法 A 掉……我很开心啊……
因此我把这道题出到了校内训练中……
在出题之前,肯定是要去把这题先做一遍的……然后,我发现我弄出了一些新的东西……!
题意简述
给出一棵无根树
你想要在树上玩一个游戏。你会做
C x y
:将 修改为 。Q k
:询问 有多少棵非空的连通子树,满足这棵子树的权值为 。输出模 。
数据范围:
时空限制:2s、128MB。
算法讨论
如果只有一次询问,非常容易想到暴力 DP。先转有根树。在全局记录答案数组
总时间复杂度为
接下来可以注意到第 2 个式子是一个“异或卷积”的形式,不难想到使用 FWT 可以优化到
再接下来就是优化修改复杂度了。看过我论文或做过 BZOJ 4712 的同学容易想到使用链分治维护树上动态 DP。首先将树进行轻重链剖分,然后按照重链构成的树的顺序进行 DP。如果这样以后每一条重链上的转移可以高效维护、支持修改,那么每次修改点
首先
可以发现
Claris 大神说这里信息可减因此不用线段树,但我觉得这里的
注意到上述算法只要求我们能求出
基于维护序列信息的算法
论文中提到的方法是转化为序列上的问题,然后使用线段树维护。由于连通子树和重链的交一定也是一段连续的链,那么我们显然就可以像最大子段和问题那样,记录
但是这个算法有一定的问题:首先它具有较大的常数因子,运行时间较慢。其次,这个算法仍然利用了具体题目的性质——连通子树和重链的交还是链。而并非所有的题都有这样的性质。最后,由于要不重不漏地计数,代码细节繁多,十分难写。
基于变换合并的算法
对于一条重链,设重链上的点按深度从小到大排序后为
(因为 没有子节点)
而我们所需要求的只有
可以观察到上面这个式子中,向量
而矩阵乘法是满足结合律的,也就是说,我们只需要用线段树支持单点修改某个矩阵
简单优化这个算法的常数。注意到形如
因此我们只需要对每个矩阵维护
比较与扩展
这两个算法的时间复杂度相同,并且都可以扩展到询问某一个有根树子树的信息——只需要对那一条重链询问一下信息和/变换和即可。
我们来审视一下后一个算法。首先,这个算法基于的是直接对这个 DP 本身进行优化这样一种思想,而不是通过分析具体题目的性质进行处理,因此这种算法具有更高的通用性。其次,由于这个算法是直接对这个 DP 本身进行优化,因此正确性显然,细节也要少于论文中介绍的在区间中维护
然而,事实上这个算法同样利用了题目的一些性质——这题是计数类问题,而且转移是线性变换,因此可以用矩阵来维护,而矩阵恰恰是一种可以合并的变换。那么对于其他的题目,是否也能用这种基于变换合并的算法呢?
BZOJ 4712 加强版(不保证修改不降)
这是一道在论文中有提到的题目。论文中介绍的算法正是一种基于标记合并的算法,其标记为
树上动态最大权独立集问题
这同样是一道在论文中有提到的题目。论文中介绍的是使用线段树维护序列上信息的方法。
考虑新的思路。记录
首先写出
考虑对这些
// 这里将 代入了
这样,我们的转移就同样是“线性变换”,可以用矩阵来维护矩阵乘法了。算法的正确性可以用将这种新定义运算的矩阵乘法展开后证明,也可以将这种算法类比为 Floyd 求最短路来理解——它和 Floyd 的实现其实是一样的。
神奇的子图
这就是论文题……
首先考虑树上的算法。记录
可以注意到,背包可以写成卷积的形式,而卷积可以写成矩阵乘法的形式,因此使用矩阵来表示变换是完全可行的。维护向量
这个算法的细节比原来的算法要少非常多,常数也小一些。
UOJ 268
终于不是论文中提到的题目了……
题意经过简化后变成这样:给出一棵树,每个点有
可以类比《神奇的子图》记录状态
转化为单点修改后,虽然要进行
神奇的简单路径
又是论文中的题了……
题意简述:给出一张图,保证每个点双
如果只有全局最长简单路径,那么就是《神奇的子图》的弱化版。现在考虑第一个询问。这种询问相当于在圆方树上做链上询问。如果是暴力的话,那么就是沿着链一个一个点 DP 上来。这种链上的 DP 显然也可以写成变换的形式,那么我们也只需要维护这条链上的变换和即可,具体实现同样用矩阵,复杂度和原算法相同。
要注意的是一个一个 DP 上来时有向上的一段和向下的一段,因此线段树中维护矩阵的积时也要维护一正一反两种信息。
总结
基于变换合并的树上动态 DP 算法,完全地采用了对 DP 本身进行优化的思想,思路较于一般的树上动态 DP 算法思路更加直观、正确性更加显然。它不仅可以通用地解决之前所有的问题,还可以获得更小的思维难度、更小的代码难度和更快的运行速度,是论文中介绍的原算法的一个很大的改进。
当然,这个算法还有一些局限性。希望大家能和我分享关于这方面的研究,希望在我们的共同努力下能有更多更好的算法出现。