树链剖分入门详解

本文介绍了树链剖分的概念,用于解决在n个节点的树上,查询和修改任意两点间权值和的问题。通过前缀和优化,将树分解为链,结合LCA(最近公共祖先)来处理不在同一链的节点。讨论了线段树在数组和树结构中的应用,解释了如何通过线段树优化单点修改和区间查询的效率。文章还阐述了树链剖分中如何选取重链以减少操作次数,并提供了从节点到根节点最多经过2*logn条链的证明。最后,详细说明了线段树的建立和修改、查询操作的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先抛出一个问题,一棵n个点的树,每个点有一个不变的权值,m次询问任意两点之间的权值和。

最简单的算法:m次循环,每次从一个点出发,dfs累计走过的路径,直到到达另外一个点。

int dfs(int x,int fa,long long deep)
{
	d[x]=deep;
	for(int i=head[x];i;i=nxt[i])
	{
		int u=to[i];if(u==fa) continue;
		dfs(u,x,deep+w[i]); 
	}
}

如果你会前缀和,将其利用到树上,将一条条链想象成数组,于是乎我们就可以快速求出在一条链上的两点之间的权值和。

对于不在一条链上的点怎么办呢?我们求一下两点(a,b)的LCA,将(a,b)分为(lca,a)和(lca,b),这样lca和每一个点都在一条链上了。

void get_treesum(int x,int fa)
{
	sum[x]=sum[fa]+a[x];
	for(int i=head[x];i;i=nxt[i])
	{
		int u=to[i];if(u==fa) continue;
		get_treesum(u,x);
	}
}
long long get_ans(int x,int y,int lca)
{
	return sum[x]+sum[y]-sum[lca]-sum[fa[lca]];
}

如果还需要你支持一种操作:修改任意一个点的权值

我们还是先考虑处理的是数组,对于数组,我们不能再使用前缀和了,否则每次修改都是o(n)的,我们就可以使用线段树或者树状

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值