图论专题-专项训练:点分治
作者:互联网
1. 前言
本篇博文是作者在学习点分治这一算法的时候做的一些题目的总结。
前置知识:点分治算法。
2. 练习题
题单:
P4178 Tree
考虑点分治。
这道题需要求的是路径长度小于等于 \(k\) 的情况,那么在点分治的 Solve
中我们需要做一点改变。
考虑建一棵值域线段树 \(Tree\) 用来维护所有当前已经出现过的路径,如果路径长度为 \(p\) 的路径出现过,那么就在值域线段树中对应的做一次单点 +1。
那么在点分治的过程中,考虑处理出所有能够出现的路径,假设当前子树处理出的路径为 \(\{tmp\}\),那么对于所有 \(tmp_i \leq k\),在线段树中查询 \([0,k - tmp_i]\) 的和就可以了。
一个优化就是如果我们每次 Solve
都要重新建一棵值域线段树,那么建树复杂度就是 \(O(k\log n)\) 的,因此我们可以考虑采用区间推平的手段,在根节点处打一个 lazy_tag 用来标记当前这一段是否全部为 0(被推平),这样每一次我们只需要在根节点处推平一次就可以了,复杂度降至 \(O(\log n)\)。
Code:Github CodeBase-of-Plozia P4178 Tree.cpp
P2634 [国家集训队]聪聪可可
考虑点分治。
首先这道题一定要看一下样例解释,否则你会发现写完了根本调不出来。
这道题需要注意的几个点:
- 聪聪和可可是可以选两个相同的点的。
- \((u,v)\) 和 \((v,u)\) 算作两个不同的点对(\(u \neq v\))。
这样,总的点对个数是 \(n^2\),我们只需要统计路径长度为 3 的倍数的路径就好。
对于 \((u,u)\) 这样的点对,显然只有 \(n\) 对,在最后计算答案的时候加上就好。
在 Solve
中开一个 \(book\) 数组来统计,其中 \(book_i\) 表示模 3 为 \(i\) 的路径有多少条。
设当前子树统计结果是 \(tmp\),那么这棵子树对答案的贡献就是 \(2 \times (tmp_0 \times book_0 + tmp1 \times book_2 + tmp2 \times book_1)+2 \times tmp_0\)。
最后的答案就是 \(\dfrac{ans+n}{n^2}\),注意约分。
Code:Github CodeBase-of-Plozia P2634 [国家集训队]聪聪可可.cpp
P4149 [IOI2011]Race
考虑点分治。
emm如果你对点分治的套路足够熟悉的话这道题就是道裸题。
我们开一个桶 \(book\),其中 \(book_i\) 表示路径长度为 \(i\) 的路径经过边数的最小值。
然后拿 \(tmp\) 做类似的玩意,转移就好了。
Code:Github CodeBase-of-Plozia P4149 [IOI2011]Race.cpp
3. 总结
点分治的题目通常都带有路径统计的特点,其考点通常在 Solve
函数上,如何设计 Solve
函数是关键。
标签:tmp,图论,路径,分治,book,Solve,聪聪,专题 来源: https://www.cnblogs.com/Plozia/p/16156545.html