dsu on tree 小结

概述

\(\text{dsu on tree}\) 是一种思想,建立在轻重链剖分之上对暴力进行合并的思想。名为树上启发式合并,还是因为它每次保留了重儿子的信息(可以看成是一种合并)。一般用于处理无修改操作的子树问题。

思路

  • 轻重链剖分出重儿子。
  • 在树上统计答案。(对于当前访问的 \(x\)
    • \(x\) 的轻儿子处统计答案,不保留其贡献。
    • \(x\) 的重儿子处统计答案,并保留其贡献。
    • \(x\) 的轻儿子的贡献加入。
    • \(x\) 是某个点的重儿子,保留其贡献,否则不保留其贡献。

时间复杂度及其证明

时间复杂度是 \(O(n \log n(f(n)+g(n)))\) 的,其中 \(f(n)\)\(g(n)\) 分别为统计答案的时间复杂度与加入贡献的时间复杂度。

证明也很简单。我们知道一个点到根的路径上只会有 \(\log n\) 条轻边。那么,一个点在加入贡献时被它的祖先所访问只会有两种情况:通过一条轻边或通过一条重边。通过轻边会访问 \(\log n\) 次,而通过重边只会访问 \(1\) 次。故时间复杂度就是 \(\log\) 的。

trick

一般可以在树上使用桶来存储一些子树相关的信息,或者使用其他数据结构。思路大体还是和暴力一样,只不过我们希望这个暴力跑的尽可能快(逃

子树相关的信息可以直接维护,但路径相关的信息因为一定在 \(\text{lca}\) 处统计所以我们需要一些技巧。考虑一种处理方式:通过 \(\text{dfs}\) 序保证不会出现在非 \(\text{lca}\) 处统计答案。

例题

CF600E,CF570D,CF208E:使用 \(\text{dsu on tree}\),开桶统计信息即可。

CF375D:开 \(\text{BIT}\) 维护信息或直接维护信息,前者 \(O(n \log^2 n)\) 后者 \(O(n \log n)\)

[IOI2011]Race:开 \(\text{map}\) 维护从 \(1\to x\) 的路径长度对应的最小深度,统计答案即可。

gym102832F:套路的,处理这种 \(i\oplus j\) 的信息,拆位开桶维护即可。

模板代码

inline void dfs1(int x,int fa) {
	sz[x]=1; son[x]=0;
	for(register int i=h[x];i;i=ver[i]) {
		int y=to[i]; if(y==fa) continue;
		dfs1(y,x); sz[x]+=sz[y];
		if(sz[son[x]]<sz[y]) son[x]=y;
	}
}
inline void upd(int x,int fa,int d) {
	...
	for(register int i=h[x];i;i=ver[i]) {
		int y=to[i]; if(y==fa||y==Son) continue;
		upd(y,x,d);
	} 
	...
}
inline void dfs2(int x,int fa,int opt) {
	for(register int i=h[x];i;i=ver[i]) {
		int y=to[i]; if(y==fa||y==son[x]) continue;
		dfs2(y,x,0);
	}
	if(son[x]) dfs2(son[x],x,1),Son=son[x];
	upd(x,fa,1); Son=0;
	...
	if(opt==0) upd(x,fa,-1);
}
posted @ 2021-02-20 09:40  tommymio  阅读(77)  评论(0)    收藏  举报