图论专题-专项训练:点分治

1. 前言

本篇博文是作者在学习点分治这一算法的时候做的一些题目的总结。

前置知识:点分治算法。

2. 练习题

题单:

P4178 Tree

考虑点分治。

这道题需要求的是路径长度小于等于 k k k 的情况,那么在点分治的 Solve 中我们需要做一点改变。

考虑建一棵值域线段树 T r e e Tree Tree 用来维护所有当前已经出现过的路径,如果路径长度为 p p p 的路径出现过,那么就在值域线段树中对应的做一次单点 +1。

那么在点分治的过程中,考虑处理出所有能够出现的路径,假设当前子树处理出的路径为 { t m p } \{tmp\} {tmp},那么对于所有 t m p i ≤ k tmp_i \leq k tmpik,在线段树中查询 [ 0 , k − t m p i ] [0,k - tmp_i] [0,ktmpi] 的和就可以了。

一个优化就是如果我们每次 Solve 都要重新建一棵值域线段树,那么建树复杂度就是 O ( k log ⁡ n ) O(k\log n) O(klogn) 的,因此我们可以考虑采用区间推平的手段,在根节点处打一个 lazy_tag 用来标记当前这一段是否全部为 0(被推平),这样每一次我们只需要在根节点处推平一次就可以了,复杂度降至 O ( log ⁡ n ) O(\log n) O(logn)

Code:Github CodeBase-of-Plozia P4178 Tree.cpp

P2634 [国家集训队]聪聪可可

考虑点分治。

首先这道题一定要看一下样例解释,否则你会发现写完了根本调不出来。

这道题需要注意的几个点:

  • 聪聪和可可是可以选两个相同的点的。
  • ( u , v ) (u,v) (u,v) ( v , u ) (v,u) (v,u) 算作两个不同的点对( u ≠ v u \neq v u=v)。

这样,总的点对个数是 n 2 n^2 n2,我们只需要统计路径长度为 3 的倍数的路径就好。

对于 ( u , u ) (u,u) (u,u) 这样的点对,显然只有 n n n 对,在最后计算答案的时候加上就好。

Solve 中开一个 b o o k book book 数组来统计,其中 b o o k i book_i booki 表示模 3 为 i i i 的路径有多少条。

设当前子树统计结果是 t m p tmp tmp,那么这棵子树对答案的贡献就是 2 × ( t m p 0 × b o o k 0 + t m p 1 × b o o k 2 + t m p 2 × b o o k 1 ) + 2 × t m p 0 2 \times (tmp_0 \times book_0 + tmp1 \times book_2 + tmp2 \times book_1)+2 \times tmp_0 2×(tmp0×book0+tmp1×book2+tmp2×book1)+2×tmp0

最后的答案就是 a n s + n n 2 \dfrac{ans+n}{n^2} n2ans+n,注意约分。

Code:Github CodeBase-of-Plozia P2634 [国家集训队]聪聪可可.cpp

P4149 [IOI2011]Race

考虑点分治。

emm如果你对点分治的套路足够熟悉的话这道题就是道裸题。

我们开一个桶 b o o k book book,其中 b o o k i book_i booki 表示路径长度为 i i i 的路径经过边数的最小值。

然后拿 t m p tmp tmp 做类似的玩意,转移就好了。

Code:Github CodeBase-of-Plozia P4149 [IOI2011]Race.cpp

3. 总结

点分治的题目通常都带有路径统计的特点,其考点通常在 Solve 函数上,如何设计 Solve 函数是关键。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值