【图论】树剖(上):重链剖分

news2024/10/6 5:41:17

一、前置知识清单

  1. 深度优先搜索DFS 点我复习
  2. 图的存储 复习链接敬请期待
  3. 树状数组 点我复习

二、树剖简介

树剖(树链剖分),是一种把树划分成链的算法,该算法分为重链剖分和长链剖分。
本文仅讨论重链剖分,长链剖分目前本人还不会,所以不予展示。

三、模拟重链剖分

图6是一棵树,我们钦定1号结点为根。
图6
图6

若要对这棵树进行重链剖分,首先要求出它的DFN序。注意这里的DFN序与DFS序还是有一定区别的。 DFN序就是优先遍历每个结点重儿子的DFS序。
以上面的图6为例,我们先求出以每个结点为根的子树重量 s i z i siz_i sizi(即以每个结点为根的子树所包含的结点个数)。该树中 s i z i siz_i sizi 分别等于 5 5 5 2 2 2 1 1 1 4 4 4 1 1 1
对于每个非叶子结点,找到其 s i z i siz_i sizi 最大的儿子(即重儿子),记为 s o n i son_i soni。若有多个儿子的 s i z i siz_i sizi 相等,则 s o n i son_i soni 取任意一个儿子均可。该树中 s o n i son_i soni 分别等于 4 4 4 3 3 3 0 0 0 2 2 2 0 0 0
我们将每个重儿子和它的父亲连接,形成一条条重链。该树中有两条重链: 1 1 1 4 4 4 2 2 2 3 3 3 为一条重链, 5 5 5 自成一条重链。

四、代码实现重链剖分

感谢@xixisuper_提供树剖代码。由于本人一顿操作,代码变得又长又唐,请见谅。

#include<bits/stdc++.h>
using namespace std;
vector<int>e[114514];
int fa[114514],dep[114514],siz[114514],son[114514];
//fa[i]存储每个非根节点的父亲,dep[i]存储每个结点的深度 
void dfs(int u,int father){
	int lz;
	fa[u]=father;
	dep[u]=dep[father]+1;
	siz[u]=1;
	lz=e[u].size();
	for(int i=0;i<lz;i++){
		if(e[u][i]==father)continue;//避免回搜 
		dfs(e[u][i],u);//本人的十手笔记本电脑写了auto会编译错误 
		siz[u]+=siz[e[u][i]];
		if(siz[son[u]]<siz[e[u][i]]) son[u]=e[u][i];
	}
}//找重儿子 
int dfn[114514],nidfn[114514],top[114514],tot;
//dfn[i]存储DFN序(点到下标),nidfn[i]存储逆DFN序(下标到点),你只需要知道这两个东西很有用就行了 
//top[i]存储链顶 
void pf(int u,int father){
	int lz; 
	dfn[u]=++tot; 
	nidfn[tot]=u;
	if(son[u]){
		top[son[u]]=top[u];
		pf(son[u],u);//先遍历重儿子 
	}
	lz=e[u].size();
	for(int i=0;i<lz;i++){
		if(e[u][i]==father)continue;//避免回搜 
		if(e[u][i]==son[u])continue;//重儿子已经遍历过了 
		top[e[u][i]]=e[u][i];
		pf(e[u][i],u);
	}
}//剖分,求DFN序 
int lowbit(int x){
	return x&(-x);
}
struct st{
	//使用树状数组维护区间和 
	int c[114514];
	void add(int x,int y){
		for(int i=x;i<=y;i+=lowbit(i))c[i]+=y;//单点修改 
		return;
	}
	void add(int x,int y,int z){
		for(int i=x;i<=y;i++)add(i,z);//这里的区间修改貌似有点怪怪的,有什么可以优化的地方请私信我,备注142719158
		return; 
	}
	int query(int x){
		int r=0;//前缀查询
		for(int i=x;i;i-=lowbit(i))r+=c[i];
		return r;
	}
	int query(int x,int y){
		return query(y)-query(x-1);//区间查询 
	}
}tr;
void update(int x,int y,int z){
	//将x与y之间唯一路径上的点点权加上z
	while(top[x]!=top[y]){
		if(dep[top[x]]>dep[top[y]]){
			tr.add(dfn[top[x]],dfn[x],z);//当两个结点不在同一条链上时,深度更大的结点向上跳 
			x=fa[top[x]];//向上跳到链顶的父亲 
		}
		else{
			tr.add(dfn[top[y]],dfn[y],z);
			y=fa[top[y]];//向上跳到链顶的父亲 
		}
	}
	if(dep[x]>dep[y])tr.add(dfn[y],dfn[x],z);
	else tr.add(dfn[x],dfn[y],z);
	return; 
}
int qry(int x,int y){
	//查询x与y之间唯一路径上的点点权之和 
	int r=0; 
	while(top[x]!=top[y]){
		if(dep[top[x]]>dep[top[y]]){
			r+=tr.query(dfn[top[x]],dfn[x]);//当两个结点不在同一条链上时,深度更大的结点向上跳 
			x=fa[top[x]];//向上跳到链顶的父亲 
		}
		else{
			r+=tr.query(dfn[top[y]],dfn[y]);
			y=fa[top[y]];//向上跳到链顶的父亲 
		}
	}
	if(dep[x]>dep[y])r+=tr.query(dfn[y],dfn[x]);
	else r+=tr.query(dfn[x],dfn[y]);
	return r;
}
int main(){
	dfs(1,0);
	top[1]=1;
	pf(1,0);
	return 0;
}

如果博客有错误,或者发现了代码中的问题,请联系我,备注142719158,我会尽快修正!鲁A济南车!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2191212.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SpringBoot的学习资源共享平台

运行环境: jdk8tomcat9mysqlIntelliJ IDEAmavennodejs 设计选用前后端分离的单体架构方式 后端&#xff1a;SpringBootMybatis-PluslogbackElasticsearchRedisMySQLJwtsmtp阿里云OSS 前端&#xff1a;WebPackVueJsAnt Designaxios 主要模块&#xff1a;反馈管理、资源管理、…

Django学习笔记二:数据库操作详解

Django框架提供了一个功能强大的ORM&#xff08;对象关系映射&#xff09;系统&#xff0c;使得开发者可以使用Python代码来操作数据库&#xff0c;而无需编写复杂的SQL语句。以下是Django数据库操作的一些基本概念和方法&#xff1a; 模型定义 在Django中&#xff0c;模型是…

大模型基础:基本概念、Prompt、RAG、Agent及多模态

随着大模型的迅猛发展&#xff0c;LLM 作为人工智能的核心力量&#xff0c;正以前所未有的方式重塑着我们的生活、学习和工作。无论是智能语音助手、自动驾驶汽车&#xff0c;还是智能决策系统&#xff0c;大模型都是幕后英雄&#xff0c;让这些看似不可思议的事情变为可能。本…

Spring源码-AOP具体源码

1.类ProxyFactory 核心方法&#xff1a;getProxy 1.DefaultAopProxyFactory#createAopProxy 判断使用JDK还是CGLIB动态代理的代码如下&#xff1a; Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {// 如果ProxyFactory的isOp…

北京市大兴区启动乐享生活 寻味大兴 美食嘉年华 系列促销费活动

北京市大兴区启动乐享生活 寻味大兴 系列促销费活动 区商务局副局长 兰莉 致开幕辞 区餐饮行业协会会长 董志明 介绍活动内容 2024年9月30日&#xff0c;由大兴区商务局主办、大兴区餐饮行业协会承办&#xff0c;并得到高米店街道和大兴绿地缤纷城大力支持的“乐享生活 寻味大…

快速排序的非递归实现:借助栈实现、借助队列实现

目录 用栈实现快速排序 1.用栈实现非递归快速排序的思路步骤 1.1.思路步骤 2.用栈实现非递归快速排序的代码 3.用栈实现非递归快速排序的整个工程 3.1.QuickSortNonR.h 3.2.QuickSortNonR.c 3.3.Stack.h 3.4.Stack.c 用队列实现非递归快速排序 1.用队列实现非递归快…

进程概念 | 进程状态 | 进程优先级

进程的基本概念 课本概念&#xff1a;程序的一个执行实例&#xff0c;正在执行的程序等。核心观点&#xff1a;担当分配系统资源&#xff08;cpu时间、内存&#xff09;的实体。 资源占用 它占用系统资源向CPU时间&#xff0c;内存等不同进程的资源是相互隔离的&#xff0c;确…

Linux中swap分区

swap 分区的创建方法演示&#xff1a; 方法1&#xff1a;fdisk &#xff08;首先查看 fdisk /dev/sda 中 swapID。由于 Linux 的 fdisk 默认会将分区的 ID 设置为 Linux 的文件系统&#xff0c;所以需要设置一下 systemID&#xff09; 解决方法 重启或者执行命令 第二个交换分…

主机可以ping通linux虚拟机但linux虚拟机无法ping通主机的解决办法

出现这个问题一般是由于物理主机的防火墙挡住了ping包&#xff0c;可以试试看把主机的防火墙关闭看看 如果可以ping通的话那么试试看添加规则将虚拟机ip添加进去 高级设置&#xff0c;入站规则&#xff0c;新建规则 下列ip地址添加虚拟机的ip地址&#xff08;使用桥接网络&…

修改Anaconda虚拟环境默认安装路径(Linux系统)

文章目录 修改Anaconda虚拟环境默认安装路径(Linux系统)1.方法一&#xff1a;使用--prefix参数2.方法二&#xff1a;配置conda环境的默认安装位置 修改Anaconda虚拟环境默认安装路径(Linux系统) 1.方法一&#xff1a;使用--prefix参数 在创建虚拟环境时&#xff0c;使用--pre…

Vue3 中Ref的最佳实践

在vue3中如果我们需要获取一个响应式的变量&#xff0c;可以使用ref来定义一个变量。 const name ref( "" );name.value "test" 定义好后&#xff0c;就可以实现修改状态&#xff0c;更新UI的效果了。 在这个基础上&#xff0c;本文主要讨论跨组件时如何…

基于STM32的智能风扇控制系统设计

引言 本项目将基于STM32微控制器设计一个智能风扇控制系统&#xff0c;通过温度传感器实时检测环境温度&#xff0c;并根据预设的温度范围自动调节风扇的转速。该系统展示了STM32的PWM输出、传感器接口以及自动控制应用的实现。 环境准备 1. 硬件设备 STM32F103C8T6 开发板…

Python 语言学习——应用1.1 数字图像处理(第一节,颜色)

目录 1.基础知识 2.实战演示 1.基础知识&#xff1a; 1.图像的表示. 函数表示&#xff1a;图像是二维信号&#xff0c;定义为二维函数f(x,y)&#xff0c;其中&#xff0c;x、y是空间坐标&#xff0c;f(x,y)是点(x,y)的幅值。拓展看&#xff0c;视频&#xff0c;又称动态图像…

SOMEIP_ETS_166: SD_TestFieldUINT8

测试目的&#xff1a; 验证DUT能够通过Getter和Setter方法正确地发送和接收TestFieldUINT8字段的值。 描述 本测试用例旨在确保DUT的ETS能够响应Tester的请求&#xff0c;正确地使用Getter方法获取TestFieldUINT8的值&#xff0c;以及使用Setter方法设置新的值。 测试拓扑&…

QGIS中怎么加载数据(如矢量shp与栅格数据)

最近有不少初学者来问我qgis里怎么加载数据 这个与arcgis中的操作其实也是类似的&#xff0c;也是通过软件的里面&#xff0b;号就行了 下面是我对这个问题的解决思路&#xff1a; 一种是直接把图层文件拖进去&#xff0c;但是这种方法很有局限性&#xff0c;下面我还说明一…

JavaWeb的小结02

第2章-第2节 一、知识点 HttpServletRequest请求对象、HttpServletResponse响应对象、响应内容类型Content-Type、请求转发、重定向、ServletContext对象。 二、目标 深刻理解HttpServletRequest对象的作用。 深刻理解HttpServletResponse对象的作用。 掌握HttpServletRequ…

什么是请求转发?

请求转发 解释 请求转发,将前端发送的请求转发到别的资源 别的资源是指: servlet,页面 即: 请求转发,可以将请求转发值另外一个servlet;也可以是将请求转发至页面 1、 请求转发演示 1.1 请求转发跳转页面 实战: 之前注册练习,修改: 实现注册完跳转到登录页面 1.2 请求转发…

【Matlab案例】imageJ + matlab 实现物体轨迹追踪及路径彩色上色

我们经常看到一些文献中对细胞或者粒子的运动轨迹进行上色&#xff0c;不同的颜色对应着不同的时间。一纯色的轨迹实现起来很方便&#xff0c;彩色的轨迹如何实现呢&#xff1f;本文使用imageJ获取轨迹数据&#xff0c;使用matlab对轨迹进行上色。结果如下&#xff1a; 1. im…

Java | Leetcode Java题解之第457题环形数组是否存在循环

题目&#xff1a; 题解&#xff1a; class Solution {public boolean circularArrayLoop(int[] nums) {int n nums.length;for (int i 0; i < n; i) {if (nums[i] 0) {continue;}int slow i, fast next(nums, i);// 判断非零且方向相同while (nums[slow] * nums[fast]…

Python爬虫(二)--http基本原理(Python Crawler (2) Basic Principles of HTTP)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…