小技巧——树

Part1

问题:统计一条根链上的点权值出现次数。

首先不难想到对根链建立主席树,可以做到 \(O(nlogn)-O(logn)\) 的优秀复杂度。
码量有些大,但它是在线算法。

离线算法
我们这样考虑:
若知道 \(x\) 的根链的点权集合,那么可以 \(O(1)\) 转移为 \(fa_x\)\(son_x\) 的根链点权集合。(本质上是莫队的思想)
于是通过离线将询问放在点上,通过一次 \(dfs\) 统计答案,点权集合用 桶 或 哈希表。
时间复杂度 \(O(n)\)
另一种思考角度:可以理解为搜索时的路径记录。

拓展问题:树上任意两点之间的链上的点权值出现次数。
这可以通过树上前缀和进行转化为根链问题。(\(ans_{x,y}=ans_{x,1}+ans_{y,1}-ans_{lca,1}-ans_{fa_{lca},1}\)

Part2

描述:\(dfs\) 序求 \(LCA\)

有些时候树剖的小常数 \(O(logn)\),已经不够用了,但欧拉序求 \(LCA\) 常数有些大。
这时便有 \(dfs\) 序求 \(LCA\)

我们回忆欧拉序,其实是通过从 \(a\) 子树到 \(b\) 子树遍历过程中,\(LCA\) 会被遍历到,因此使用 \(RMQ\) 询问。
现在使用 \(dfs\) 序,从 \(a\) 子树到 \(b\) 子树遍历中,如何存储 \(LCA\)?
我们存储 \(fa_x\),查询 \([dfn_x+1,dfn_y]\)\(dep\)\(dfn\) 最小的点。

代码:

#include<iostream>
#include<vector>
using namespace std;
constexpr int N=5e5+5;
int n,m,s,ST[20][N],dfn[N],cnt,log[N];
vector<int> v[N];
int gt(int x,int y){ return (dfn[x]<dfn[y])?x:y; }
void dfs(int x,int f){
	ST[0][dfn[x]=++cnt]=f;
	for(int u:v[x])if(u!=f)dfs(u,x);
}void build(){
	log[0]=-1;
	for(int i=1;i<=n;i++)log[i]=log[i>>1]+1;
	for(int i=1;i<=log[n];i++)
		for(int j=1;j+(1<<i)<=n+1;j++)
			ST[i][j]=gt(ST[i-1][j],ST[i-1][j+(1<<(i-1))]);
}int LCA(int x,int y){
	if(x==y)return x; x=dfn[x],y=dfn[y];
	if(x>y)swap(x,y); int k=log[y-(x++)];
	return gt(ST[k][x],ST[k][y-(1<<k)+1]);
}signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); 
	cin>>n>>m>>s;
	for(int i=1,x,y;i<n;i++)
		cin>>x>>y,v[x].push_back(y),v[y].push_back(x);
	dfs(s,0),build(); 
	for(int i=1,x,y;i<=m;i++)
		cin>>x>>y,cout<<LCA(x,y)<<'\n';
	return 0;
}

Part3

描述:树的三度化
作用:将一棵带权树,在保证任意两点距离不变的情况下,转化为每个节点度数最多为 3 的树。

考虑无权多叉树转二叉树:左儿子、右兄弟。
我们不妨在每条边上设置虚点用于连边,具体的如下图所示:


可以看到,通过构造边权为 0 的边从而使度数减少,其实是用点换度数。
可以证明,总共有 \(2n-1\) 个点。

注意:三度化会大幅增加树的深度,需要配合 树剖/点分树 食用。

Part4

描述:树上二分
当一些答案具有单调性,如带权树的重心,可以进行二分。

具体地,考虑树的重心,可以将问题规模减半,实现 \(logn\) 的复杂度。
建立点分树,通过点分树上查找进行二分。
由于答案只能通过相邻边转移,可以在建立点分树时记录一个 \(pre\) 数组。
含义为 \(pre_rot=son_x=u\),即 \(rot\)\(x\) 在点分树上的儿子,\(u\)\(x\) 在原树上的的儿子,且 \(u\) 子树的重心为 \(rot\)

由于需要遍历点分树上节点 \(x\) 的所有儿子,所以复杂度与结点度数有关,建议使用三度化。

posted @ 2025-11-21 23:07  zhoumengxuan  阅读(6)  评论(0)    收藏  举报