ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

轻重链剖分

2022-02-05 01:00:24  阅读:173  来源: 互联网

标签:链剖分 子树 int son dfn 轻重


目录

轻重链剖分

论文鸽说叫 heavy-light decomposition 或 heavy path decomposition .

正确叫法(不是):

这是真的:

轻重链剖分基本原理

一个节点子树大小最大的儿子叫重儿子 .

节点到重儿子的边叫重边 .

一堆重边叫重链 .

重儿子优先 DFS,于是重链连续,每条链可以拆成若干条重链和杂边 .

每次走轻儿子子树大小至少除以二,于是每条链可以拆成 \(\log\) 条重链,用线段树维护 DFS 序就可以做到 \(\log^2\) .

这就是轻重链剖分的基本原理 .

代码实现(板子)

题面

LOJ139 树链剖分

维护一棵 \(n\) 个点有点权的树,支持

  • 换根
  • 路径修改
  • 子树修改
  • 路径和
  • 子树和

换根影响

树上两点间路径唯一,于是路径啥事没有

换根对子树的影响可以看 树 社论 的做法,就是拆成子树补啥的 .

于是做完了 .

轻重链剖分

轻重链剖分通过两次 dfs 完成,非常好理解吧 .

整理一下要维护的东西:

  • 父亲
  • 深度
  • 子树大小
  • 重儿子
  • 所在重链顶端节点(top
  • DFS 序相关

Code:

void dfs1(int u)
{
	siz[u] = 1;
	for (int v : g[u])
	{
		if (v == fa[u]) continue;
		fa[v] = u;
		dep[v] = dep[u] + 1;
		dfs1(v);
		siz[u] += siz[v];
		if (!son[u] || (siz[v] > siz[son[u]])) son[u] = v;
	}
}
void dfs2(int u, int t)
{
	top[u] = t;
	rnk[++cc] = u; dfn[u] = cc;
	if (!son[u]) return ;
	dfs2(son[u], t);
	for (int v : g[u])
		if ((v != son[u]) && (v != fa[u])) dfs2(v, v);
}

链操作

查询修改类似

ll query(int u, int v)
{
	ll ans = 0, fu = top[u], fv = top[v];
	while (fu != fv)
	{
		if (dep[fu] > dep[fv]){ans += T.query(1, dfn[fu], dfn[u]); u = fa[fu];}
		else{ans += T.query(1, dfn[fv], dfn[v]); v = fa[fv];}
		fu = top[u]; fv = top[v];
	}
	if (dfn[u] > dfn[v]) swap(u, v);
	return ans + T.query(1, dfn[u], dfn[v]);
}

可以精简代码です

子树操作

DFS 序板子,略过 .

整体代码

Welcome to OI!

树剖完就是线段树题了qwq

没了

题外话

——《Segment Tree Beats!》
应该是圆方树解决吧 .

标签:链剖分,子树,int,son,dfn,轻重
来源: https://www.cnblogs.com/CDOI-24374/p/15863743.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有