标签:family dfs序 线段树 刷题 span 自己 描述 维护 逆运算
说实话这道题没有A掉,不过所有的思路都是我自己想的,我觉得这个思路真的很棒很棒很棒的。
首先这个题的题面描述告诉我这种运算有封闭性,满足结合律和交换率,那么其实这个东西是个群运算了,而且这个群有单位元和逆元,那我们就可以针对题中的运算制造逆运算。
然后考虑树桶dp。
我们发现当所有的x都是0的时候,可以直接简单的换根dp。
然而x不为0的时候我们就必须对路径上的每个点做一个反处理,让相应的点不能被同时加入路径。
首先考虑用线段树维护每个点的树桶。那么复杂度是$O(klogn)$的。
我们每次归并一个儿子就在线段树上打上相应的贡献。
然后发现因为对于每个点来说,他的父链必然不是敌人,那么我们考虑对于以每一个点为$lca$的路径的贡献。
那么其实我们固定了一条以当前这个lca为顶的链之后,所有的敌人的子树是确定的了,那么我们在线段树上ban掉这个子树(dfs序连续一段),然后在lca的子树区间中查询线段树,没有归并进来的儿子不被计算,计算的是当前这个还没有归并进来的儿子所形成的链和其他已经归并了的儿子的链组成的路径的贡献,把这个贡献*2就是这条路经正反向的贡献。
这样复杂度是$O(n^2klogn)$的。
考虑重链划分来优化。
用两种dfs,大的和小的,大的套小的。
我们先在大dfs中,大dfs他的重儿子然后不进行小dfs,在线段树上加入重儿子的贡献,之后遍历当前点的每一个轻儿子,先进行小dfs,按照上面那种套路来形成链,同时在线段树上查询。
我们发现漏了一部分的贡献,就是重儿子到他所在和重链的所有父辈节点的路径贡献没有计算,树剖复杂度是$O(log^2)$的,但是注意到重链只有一条,可以直接在线段树上查询这条重链从这个重儿子到链顶的贡献,*2即可。
注意到重儿子没有进行小dfs,也就是说他只进行了一次大dfs,是启发式合并的复杂度。
那么总复杂度是$O(nklog^2n)$
不能通过本题,不过我喜欢这个算法。
标签:family dfs序 线段树 刷题 span 自己 描述 维护 逆运算
原文地址:https://www.cnblogs.com/Lrefrain/p/11437269.html