点分治口胡

点分治学习语文学习

大致功能

计算静态树上的符合条件的路径的数量,长度等
eg

  • 统计长度小于k的路径数量
  • 经过特殊点不超过𝑘个的最长路径长度
so为什么要用点分治呢?

路径经过两个点的lca,于是就被分成了两段!
统计答案的时候,实际上是找两段经过lca的路径配对,看合不合法。
分治,核心思想就是分成几个子问题求解,这几个子问题与总问题有一定的关联,综合起来就可以得出这个问题的解
这些路径端点都在子树中,子树中也有路径,总的情况与这些子树的情况是相关的,所以分别统计子树的情况,一通乱搞 就可以得出整个问题的解。
所以点分治便是起到了将总问题转化为子问题的作用

基本原理

对某棵正在处理的树,指定一个根root(重心)分别统计它的子树中的路径(点对),将这些子问题的答案综合起来,得到这棵树的答案
统计的方法大致分为两种

正难则反

首先,所有点到根的路径两两配对,归类为过根可重路径
显然这种路径分为两种:
1.起点和终点不在一棵子树中
2.在一棵中
直接算第一种的数量,势必要分C(nson,2)种情况,要用数据结构维护前面的情况,有些题目没必要
那么就借助容斥原理,用总的减掉不合法的,也就是第二种呗
第二种又等价于什么呢
设root的儿子为v,假设树已分层,儿子的层数较大
数量不就等于这棵子树中所有的过v可重路径吗!
这里注意统计的还是子树中的点到root的距离,所以要加起始距离,也就是到儿子的边权
(注意,是过v,不是过v的向下子树的实际的根(重心)!)
妙啊

直接统计

维护一个数据结构,记录已统计的子树的情况,统计新的子树时,便可找出与正在统计的路径(点)配对后符合条件的最优解或方案数,统计完这棵树后,再去更新数据结构
那么为什么要重心当根呢?如果直接把儿子当根的话,树每次分成的子树大小相差太大,有可能每次只分出非常小的几棵和非常大的一棵,所以分一棵的时候,复杂度可能会从log变成n,所以总的复杂度就呵呵了
所以要让这个根的子树的大小尽可能平均,所以可以选择重心作为某棵子树的根,相当于把这棵子树砍下来,把重心提起来,对他在进行分治!

O(n) 求重心的方法:

dfs遍历,(假设给树分层)计算每个点的向下子树的大小,若某个点的儿子的向下子树和父亲的向上子树的大小的最大值更小,则将根更新为它
那么,点分治间接统计的总的步骤就是这样:

1.求出根𝑟𝑜𝑜𝑡

2.得到相关信息,统计第1类路径并累加入答案中

3.删除节点𝑟𝑜𝑜𝑡,对于𝑟𝑜𝑜𝑡的每一棵子树递归的执行分治算法

so 点分治最重要的思想是分治吗?

我这么问当然就不是的拉
我们的任务是统计
那么在什么里面寻找最方便呢?
当然是除了某个东西的属性之外,其他的特征比如顺序,结构什么都不用管的东西拉
要计数的话,直接做加减法最方便
要维护最值的话,只用考虑每个东西的值
那这个东西不就是

集合

吗?
(以下叙述引自三水)
“树有结构特征,有些点是等价的,而有些点不是。无根树的等价就是存在一种 点到点的映射使得两棵树完全一致
而树的结构非常多 所以在处理树上的问题的时候 往往都需要dfs 在获取树的结构信息之后才能去处理 比如如果暴力的去枚举每一个点对的话 每一次求解 其实都需要跑一次dfs才能得到这条路径
这是由树的结构决定
如果能把他转换成一个在集合上的问题 那么在操作的时候 所有基于树的结构信息都被忽略且不会对结果产生影响
在同一颗子树中“是唯一对结果会产生影响的结构信息“
所以把过root的路径记为一个点对,放到一个集合中,这种思想就太巧妙了!利用容斥原理,把不符合的减掉,剩下的不就是答案吗!

应用

主要是思考如何设计统计的函数
一. 统计长度小于k的路径数
luoguP4178
间接法尺取法+单调性:可以On求数组中满足某个约束的数对的数量
二.经过特殊点不超过𝑘个的最长路径长度

#include <bits/stdc++.h>
using namespace std;
int n,k,e,root,ans,sizenow,size[200004],tmpdis[200004],maxsonsize[200004],head[200004],dis[200004];
bool isroot[200004];
struct node{
   
	int v,next,w;
}a[200001
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值