『树链剖分』原理及简单应用

树的重链剖分

我们可以把一个树剖分为若干条链,按照如下规则剖分可以得到的结论是:树上任意两点间的的链数一定不超过 l o g n log_n logn条。证明略。

  • 将每一个节点的重儿子和自己为一个链内。一个节点的轻儿子单独成为链的开端。
  • 其中重儿子为 s i z e size size最大的节点,轻儿子为不是重儿子的儿子。

具体的代码可以这样实现:

void dfs1(int x,int fa)
{
   
	size[x] = 1, dep[x] = dep[fa]+1;
	for (int i=0,y;i<G[x].size();++i) 
	{
   
		if ((y = G[x][i]) == fa) continue;
		f[y][0] = x, dfs1(y,x), size[x] += size[y];
		if (size[y] > size[son[x]]) son[x] = y;
	}
	return;
}

由于树链剖分的作用是处理树上的路径问题,因此我们有必要通过树链剖分将树转化为链。

如果我们进行深度优先遍历,且优先遍历重儿子,那么一条路径一定可以在树的DFS序中分成连续的若干段。我们也可以借此记录每一段----的段头。

就像这样:

void dfs2(int x,int cur)
{
   
	dfn[L[x] = ++tot] = x, top[x] = cur;
	if (son[x] > 0) dfs2(son[x],cur);
	for (int i=0,y;i<G[x].size();++i)
	{
   
		y = G[x][i];
		if (y != f[x][0] && y != son[x]) dfs2(y,y);
	}
	R[x] = tot;
	return;
}

如果我们需要处理想点间的路径操作,我们可以这样实现:

void query(int x,int y)
{
   
	while (top[x] ^ top[y])
	{
   
		if (deep[top[x]] < deep[top[y]]) 
		    x ^
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值