传送门
神仙题。。简单版本很好做,做法也很多。
加强版\(n\leq 10^5\),显然之前的\(O(n^2)\)的做法时间、空间复杂度都不能承受。
考虑维护以深度有关的\(dp\):
- \(f[i][j]\)表示以\(i\)为根节点的子树中,深度为\(j\)的点有多少个。
显然这个很好维护,转移\(\displaystyle f[i][j]=\sum_{k}f[k][j-1]\),我们可以用长链剖分加速。
因为我们要枚举\(3\)个点,现在还需要一个\(dp\)维护另外两个点的信息。
- \(g[i][j]\)表示以\(i\)为根节点的子树中,点对\((x,y)\)的个数有多少个,点对要满足\(x,y,x\not ={y}\)到\(lca\)的距离相等,并且从\(lca\)到\(i\)这段距离为\(d-j\)。也就是说还需要一条长度为\(j\)的链进行匹配。
考虑如何转移:
- 显然可以直接从儿子进行转移,即\(g[i][j]=g[k][j+1]\);
- 从不同儿子子树中选取两个:\(g[i][j]=f[k_1][j-1]*f[k_2][j-1]\)。此时两个结点的\(lca\)一定为\(i\)。
注意第一种转移跟深度有关系,但是和之前有点区别,此处我们还是可以通过长链剖分来进行优化;第二种转移可以直接进行枚举,这里枚举的深度会受到限制,总的枚举次数为\(O(长链长度)\)。
之后考虑如何维护答案。
显然最终的答案有两种情况:
- 中心点为某一个结点,此时答案为\(g[i][0]\);
- 中心点不为某一个结点,此时答案为\(f[i][j]*g[k][j+1]+f[k][j-1]*g[i][j]\)。主要就考虑了\((2,1),(1,2)\)这两种情况,其实\((1,1,1)\)这种也考虑了的,但已经被包含入\((2,1)\)了。
以上过程我们在一边枚举轻儿子时一边进行转移&统计答案。
注意\(g[i][0]\)要先加上,否则可能会重复统计。
细节见代码:
/*
* Author: heyuhhh
* Created Time: 2020/6/10 23:23:27
*/
#include
#include
#include
#include
#include
#include
#include
#include