题目大意
给出一棵树,每个节点有一个权值,这个数的根节点会改变,每次查询两颗子树中各取一个节点的值相同的方案数.
分析
先转换一下问题,取出的节点的值相同的方案数 \(=\sum_{i=1}^n(count(i,x)\times 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\) 分还是挺容易做到的).