作者:广东快乐笨人 | 来源:互联网 | 2023-10-17 18:26
本文由编程笔记#小编为大家整理,主要介绍了「Luogu P4689 [Ynoi2016]这是我自己的发明」相关的知识,希望对你有一定的参考价值。
题目大意
给出一棵树,每个节点有一个权值,这个数的根节点会改变,每次查询两颗子树中各取一个节点的值相同的方案数.
分析
先转换一下问题,取出的节点的值相同的方案数 (=sum_{i=1}^n(count(i,x) imes count(i,y)))(其中 (count(a,b)) 表示在 (b) 的子树中值 (a) 出现的次数).
然后就变成了一个和 P5268 差不多的一个问题.
在 DFS 序中查询的子树必定为其中的一段区间或者两段区间(其中一段的一端为头,另一段的一端为尾).
对于拆成最多 (16) 个区间的做法这里就不多说了,这里就分享一个只需要拆成 (4) 个区间的大常数做法以及一个可能有点用的卡常方法.
对于拆出来的两个区间都是从数列的边上开始,那么这个东西看起来就像是一个环,那么就可以用处理环的方法处理这个东西,对于 ([1,a]) 和 ([b,n])((a) 这样两段区间可以先将原序列变成两个相连的原序列,那么这两个区间就变成了 ([b,n+a]),变成了一个区间就比较好处理了(但是这里的 (n) 相当于乘了 (2) 所以常数巨大实测基本会 TLE).
考虑 lxl 是毒瘤,所以数据也会很毒瘤,对于最多拆 (16) 个区间的方法可能会卡满,那么考虑最开始建树的时候随机一个节点为 (root) 建树,对于运气好的时候可以跑飞快.
利用上面两个方法确实是可以通过这道题的(但不能做到次次过).
代码太丑了,想要看的点这里吧(我觉得 (60) 分还是挺容易做到的).