「Luogu P4689 [Ynoi2016]这是我自己的发明」

题目大意

给出一棵树,每个节点有一个权值,这个数的根节点会改变,每次查询两颗子树中各取一个节点的值相同的方案数.

分析

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

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

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

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

posted @ 2020-06-02 11:34  SxyLimit  阅读(173)  评论(0编辑  收藏  举报