「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)) 这样两段区间可以先将原序列变成两个相连的原序列,那么这两个区间就变成了 ([b,n+a]),变成了一个区间就比较好处理了(但是这里的 (n) 相当于乘了 (2) 所以常数巨大实测基本会 TLE).

考虑 lxl 是毒瘤,所以数据也会很毒瘤,对于最多拆 (16) 个区间的方法可能会卡满,那么考虑最开始建树的时候随机一个节点为 (root) 建树,对于运气好的时候可以跑飞快.

利用上面两个方法确实是可以通过这道题的(但不能做到次次过).

代码太丑了,想要看的点这里吧(我觉得 (60) 分还是挺容易做到的).

原文地址:https://www.cnblogs.com/Sxy_Limit/p/13030223.html