树分块学习笔记
树分块学习笔记
引言
在大多数时候,树上问题可以使用树剖、动态树和树分治进行解决,但在一些的特殊的情况下,或者在数据范围较为宽松的情况下,树分块也是一种不错的选择。
算法概述
和序列问题一样,树分块是一种暴力的暴力,大致思想就是将树上的点每次划分进
而基于不同的题目,会有很多种不同的分块方法。在一般情况下,树分块在处理树的路径等具有连通性质的问题时表现较为强力。
法一:
按照 DFS 序进行划分,不能保证直径长度和块联通,一般用于处理子树信息,在处理其它信息时较为乏力。
法二:
检查当前节点的父亲所在块的大小,如果小于
例题:
给定一棵树,树上每个点有一个权值,需要支持修改点权和查路径最小值。
经典的树剖/LCT 板子题,这里使用树分块解决:
按本方法分块,对于每个点记录它到块内深度最小的点路径上的答案。
查询时会在 LCA 处多出一个零散快,需要注意。
修改直接修改块内答案即可。
复杂度
法三:
随机找
例题:
bzoj2589/SP10707 Count on a tree II
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
这个题就是该分块方法的经典应用,因为我们想要块联通且块数量不超过
这个题的解题方法也有很多,这里提供其中一种。
我们分块以后的每个询问被拆成了两个零散块和一个整块,我们记两个零散块所构成的集合分别为
然后发现
复杂度
法四:
引题:
[SCOI2005]王室联邦
“余”人国的国王想重新编制他的国家。他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成 员来管理。他的国家有n个城市,编号为1..n。一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条 直接或间接的道路。为了防止管理太过分散,每个省至少要有B个城市,为了能有效的管理,每个省最多只有3B个 城市。每个省必须有一个省会,这个省会可以位于省内,也可以在该省外。但是该省的任意一个城市到达省会所经 过的道路上的城市(除了最后一个城市,即该省省会)都必须属于该省。一个城市可以作为多个省的省会。聪明的 你快帮帮这个国王吧!
方法:按 dfs 逆后序入栈,如果当前节点的子树大小大于
感觉讲的有点抽象,可以结合代码理解:
void dfs(int x,int fa){
int now=ls;
for(rg int i=head[x];i;i=e[i].nxt){
int y=e[i].node;
if(y==fa)continue;
dfs(y,x);
if(ls-now>=B){
rt[++ans]=x;
while(ls>now){
bl[s[ls]]=ans;
ls--;
}
}
}
s[++ls]=x;
}
这个方法可以很好地结合树上莫队进行使用。
结语
希望大家可以在本篇博客中略有收获吧。