首页 > 其他分享 >链剖分

链剖分

时间:2024-02-03 23:23:36浏览次数:22  
标签:链剖分 sz int top DFS son 重链

重链剖分

image

第一次 DFS 求重儿子(子节点更多的儿子)。

第二次 DFS 求重链剖分(先访问重儿子再访问其他轻儿子)。

变量:重儿子,子树大小,DFS 序(\(x\) 根子树 DFS 序中第一次出现位置),以 \(x\) 为根的子树的最后一次出现位置,深度,\(x\) 所在重链的顶端。

void dfs1(int x){//求出重儿子,sz[v] 最大的一个
	sz[x]=1;
	for(auto v:g[x]){
		if(v==fa[x])continue;
		dep[v]=dep[x]+1;//深度
		fa[v]=x;
		dfs1(v);
		sz[x]+=sz[v];
		if(sz[v]>sz[son[x]])som[x]=v;//大于当前重儿子
	}
}

/*
st[x] DFS 序($x$ 根子树 DFS 序中第一次出现位置)
ed[x] 以 $x$ 为根的子树的最后一次出现位置
top[x] $x$ 所在重链的顶端
*/

void dfs2(int x){//求 dfs 序
	st[x]=ed[x]=++dc;
	if(!son[x])return;//叶子节点
	top[son[x]]=top[x];
	dfs2(son[x]);
	for(auto v:g[x]){
		if(v==fa[x]||v==son[x])continue;
		top[v]=v;
		dfs2(v);
	}
	ed[x]=dc;
}

性质:

一条重链上所有点在 DFS 序上连续;

任意点 \(x\) 到根的路径上经过的轻边数量不超过 \(log(n)\)。

求 LCA。

每次向上跳所在重链顶端较深的,直到 \(x,y\) 在同一条重链上,深度较浅的是 LCA。

轻儿子 \(top\) 等于自己。

int LCA(int x,int y){
	while(top[x]!=top[y]){//不在一条重链上
		if(dep[top[x]]<dep[top[y]])
			std::swap(x,y);//重链顶端更浅的
        x=fa[top[x]];
        //top[x] 一定是轻儿子
        //fa[top[x]] 重儿子,在重链上
        //fa[top[x]] 轻儿子,top[fa[top[x]]]=fa[top[x]],再跳 fa 再跳过一个轻边
	}
	return dep[x]<dep[y]?x:y;
}

重链剖分模版:

支持操作:换根,修改路径权值,修改子树权值,询问路径或子树。

image

只需考虑子树,不用考虑 \(fa\) 和重链。

image

标签:链剖分,sz,int,top,DFS,son,重链
From: https://www.cnblogs.com/CheZiHe929/p/18005398

相关文章

  • 树链剖分
    son[x]表示节点\(x\)的重儿子,若为\(0\),则说明\(x\)为叶子节点id[x]表示节点\(x\)的dfs序编号f[x]表示节点\(x\)的父节点dep[x]表示节点\(x\)的深度sz[x]表示节点为\(x\)的子树的大小top[x]表示x所在重链顶部的节点函数原型voiddfs1(llu,llfa)功能:计算dep[]、f[]、sz[]和......
  • 【动态规划】长链剖分优化树形 dp
    我们在树形dp中经常会遇到这样一个模型:设\(f_{x,i}\)表示节点\(x\)的子树中深度为\(x\)的答案...有递推式:\(f_{x,i}=\sum_{son}f_{son,i-1/i+1}\dots\)。这样直接做是\(\Theta(n^2)\)的,我们考虑去优化这个dp。有一个小优化,就是我们想让\(f_x\)直接继承......
  • 【树链剖分】P3401 洛谷树 题解
    P3401考虑先将路径权值进行转化,因为很难对路径直接进行统计。考虑如何表示出这条路径的权值。记\(s_i=\oplus_{j\in\text{path}(1,i)}w_j\),其中\(\text{path}(i,j)\)表示\(i\)到\(j\)的路径上的边集。则\(u\tov\)的路径的权值为\(s_u\opluss_v\)。现在转变为......
  • 重链剖分的另一个性质
    我们大家都知道树的节点深度和是比树的节点高度和要大的,这个直观感受一下就能理解。什么时候这俩东西一样呢?答案是树形态形如一条链的时候。回忆重链剖分,重链剖分的一个性质是如果说我们把所有重链缩成一个点,形成的新树上节点深度最大是\(\logn\)级别,当然用完全二叉树就能把深......
  • 树链剖分
    树链剖分一、树链剖分的概念和写法1.1概念定义:树链剖分用于将树分割成若干条链的形式,以维护树上路径的信息。具体来说,将整棵树剖分为若干条链,使它组合成线性结构,然后用其他的数据结构维护信息。树链剖分(树剖/链剖)有多种形式,如重链剖分,长链剖分和用于Link/cutTree的剖分(有......
  • 重链剖分
    前置芝士:线段树,或树状数组,越熟练越好。(当然这不是意味着你不会线段树就看不懂这篇博客。)1.何为树链剖分树链剖分,简而言之,就是将树分成一条条链,然后用数据结构去维护这些链,以支持树上两点间的各种询问操作。据我所知,树链剖分大约有三种,分别是重链剖分、长链剖分和实链剖分。其......
  • 树链剖分
    注意事项:线段树中\(modify(),query()\)中\(>=,<=,>,<\)以及\(l,r,L,R\)#include<bits/stdc++.h>#definelsp<<1#definersp<<1|1#definelsonls,l,mid#definersonrs,mid+1,r#defineroot1,1,nusingnamespacestd;constint......
  • 树链剖分 学习心得
    Bug都写在代码开头了,就不复述了。还有一个智障的错误是注释调试代码的时候把同一行的正式代码也给注释掉了(写得非常精彩。/*  bug:1.rev、id要分清!      2.mod()函数的情况不能写一半就跑路!      3.别忘了先给tree build()一下!      4.出界......
  • 重链剖分
    代码思路主体部分:初始化,剖分链,求LCA(也就是dfs1,dfs2,LCA三个函数)辅助部分:structPoint{//节点信息多的时候会习惯开个结构体来存 intdep,siz,son,top,fath; //点的深度子树大小重儿子所在重链的链头父亲节点 //没有重儿子则son=0 intid,l,r;//求lca不......
  • 树链剖分【产品说明书】
    一种暴论:树链剖分=多叉树上分块+线段树适用范围总之就是数据结构的基础问题。总的来说,树链剖分可以在\(O(m\logn)\)的时间复杂度中,解决大多数树上路径问题,包括其修改、维护和查询。例如这样的一道模板题又例如……(请直接跳到本文最后一章)产品简介树链剖分有两种:重......