CC's

Back

今天仍然是被吊起来打的一天。

点分治是一种用于解决树上路径问题的思路。它的关键就是选中一点,统计经过该点的答案后删除点,再递归到两个子树中进行同样的操作。

删除的点连带删除了一些已经计算过的路径。

当每次选择重心作为根时,能保证点分治的复杂度本身为O(nlogn)O(n \log n)。当然你得保证O(n)O(n)做完你的事情,同样清数组时也必须只清用到的

印象里之前有道树上DP的题,自己yy瞎糊的算法写的难看又难调,就有点这种感觉。不过那个是O(n)O(n)的,大概泛用上不如这个。

聪聪可可#

聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。

他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画 nn 个“点”,并用 n-1n−1 条“边”把这 nn 个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是 33 的倍数,则判聪聪赢,否则可可赢。

聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。

分析#

统计路径。但是这题dp的话能转移。

但是还是用点分治。

枚举一个点后,设f(u,j)f(u,j)表示到uu点模3为jj的路径数有多少。转移很明显,统计也很显然。

[HDU6643] yts1999 Doesn’t Like This Problem#

Mr. Bread has a tree T with n vertices, labeled by 1,2,…,n. Each vertex of the tree has a positive integer value wi.

The value of a non-empty tree T is equal to w1×w2×⋯×wn. A subtree of T is a connected subgraph of T that is also a tree.

Please write a program to calculate the number of non-empty subtrees of T whose values are not larger than a given number m.

分析#

虽然我不知道为什么就显然点分治了,但是他们说是。要DP还是容易看出来的。

点分治能够解决路径问题,这种连通性问题也可以解决。也是枚举一个点后,统计包括这个点的连通块的答案。

选中该点后,进行DP。然后是他们说的非常套路的利用dfs序将树映射到序列上的做法。以f(i,j)f(i,j)表示在ii点处值为jj的方案数。

选中ii

f(i,ja)+=f(i+1,a)f(i,ja)+=f(i+1,a)

不选ii,那么同时要跳过i的整个子树:

f(i,j)+=f(i+sz(i),j)f(i,j)+=f(i+\text{sz}(i),j)

另外是这道题的jj范围太大。看到一个很骚的写法是存成jjM/jM/j,然后每个都只有M\sqrt M这么大…我寻思你再给我一遍这个题我也yy不出来这种存法。

总之有两个东西可以注意一下:

  • 对树上涉及依赖关系的DP可以考虑使用dfs序映射。
  • 我不知道这个处理j的办法有没有泛用性。

代码#

代码中的重心、点分治的solve应该形成较为固定的写法。

origin

一点点点分治
https://astro-pure.js.org/blog/a-littile-tree-divide
Author Cheng Chen
Published at 2020年3月26日
Comment seems to stuck. Try to refresh?✨