当前位置: 首页 > news >正文

树链剖分(重链剖分)

树链剖分的核心思想就是将一棵树剖分成一条一条的链

因为树不好处理 但链比较好处理

为了学会它 我们先要学会树上dfs(深度优先搜索) 然后就没了(雾)

Because 树链剖分需要用到两个dfs

哦对了 我们还要了解以下的知识点

1.子树大小

就是一个节点的子树的节点个数(包括它自己)

2.重儿子

一个节点的所有儿子中子树大小最大的儿子

3.轻儿子

除了重儿子之外的儿子(包括根节点)

4.重边

两个相邻的重儿子连成的边

5.重链

重边连成的链(开头是轻儿子)

OK,了解完了

启动!

dfs1:

目标是求出以下数据

1: 节点的父节点 fa[x]

2: 节点的深度 也就是它到根节点的距离 deep[x]

3: 节点的重儿子 son[x]

4: 节点的子树大小 si[x]

思路十分的简单 直接上代码

void dfs1(int x)
{deep[x]=deep[fa[x]]+1;si[x]=1;//它自己也是 for(int i=0;i<a[x].size();i++){if(a[x][i]==fa[x]) continue;fa[a[x][i]]=x;dfs1(a[x][i]);si[x]+=si[a[x][i]];if(si[a[x][i]]>si[son[x]]) son[x]=a[x][i];}
}

dfs2:

目标是求出以下数据

1: 节点的所在的重链的顶端节点 top[x]

2: 节点的新编号 id[x]

3: 节点的新编号的值 b[x]

其中 新编号的原则是先走重儿子 再走轻儿子(理由下次一定)

比如

懂了吗? 我相信你肯定懂了

思路也十分的简单 直接上代码

​
void dfs2(int x,int topf)
{id[x]=++cnt;top[x]=topf;b[cnt]=w[x];if(!son[x]) return;dfs2(son[x],topf);for(int i=0;i<a[x].size();i++){if(a[x][i]==fa[x]||a[x][i]==son[x]){continue;}dfs2(a[x][i],a[x][i]);}
}​

我们发现先走重儿子的话 就可以让重链上的点的新编号是连续的 也就形成了一条链

至此 树链剖分就结束了

那你一定很想问 这玩意有什么用呢?

题目

我们结合题目来看(其实是模板)

前置芝士:线段树

让我们处理4种操作

我们先来看操作3和操作4

通过观察图片可以看出

一个节点的子树的编号肯定是连续的

设子树的根是x

左端点是的编号是x 右端点的编号是x+si[x]-1

所以3操作就是将xx+si[x]-1加上z

4操作就是求出xx+si[x]-1的值的和

即区间修改 ,区间查询

我们当然会想到线段树啦

直接拿下

之后我们来看1,2操作

先来看一看图

比如我们要从 7 到 4

我们可以先判断它俩的top是不是一个东西 发现不是 

发现4的深度比7小 这怎么可以呢?

我们交换一下 变成从 4 到 7

然后把4跳到它的top的父节点

也就是0(1的父节点是0)

并加上 1 到 4 的值 可以用线段树处理

之后在循环上述操作

直到两者的top相等

上代码

int getsum1(int x,int y)
{int sum=0;while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]]){swap(x,y);}sum=sum+query(1,1,n,id[top[x]],id[x]);x=fa[top[x]];}if(deep[x]>deep[y]){swap(x,y);}sum+=query(1,1,n,id[x],id[y]);return sum;
}

修改也差不多 直接上代码

void addsum1(int x,int y,int z)
{while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]]){swap(x,y);}add(1,1,n,id[top[x]],id[x],z);x=fa[top[x]];}if(deep[x]>deep[y]){swap(x,y);}add(1,1,n,id[x],id[y],z);
}

完整版:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,cnt,m,r,mod;
int b[110000],top[110000],w[110000],deep[110000],id[110000],fa[110000],si[110000],son[110000],tr[410000],tag[410000];
vector<int>a[110000];
void dfs1(int x)
{deep[x]=deep[fa[x]]+1;si[x]=1;//它自己也是 for(int i=0;i<a[x].size();i++){if(a[x][i]==fa[x]) continue;fa[a[x][i]]=x;dfs1(a[x][i]);si[x]+=si[a[x][i]];if(si[a[x][i]]>si[son[x]]) son[x]=a[x][i];}
}
void dfs2(int x,int topf)
{id[x]=++cnt;top[x]=topf;b[cnt]=w[x];if(!son[x]) return;dfs2(son[x],topf);for(int i=0;i<a[x].size();i++){if(a[x][i]==fa[x]||a[x][i]==son[x]){continue;}dfs2(a[x][i],a[x][i]);}
}
void build(int k,int l,int r)
{if(l==r){tr[k]=b[l];return;}int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);tr[k]=tr[k<<1]+tr[k<<1|1];
}
void push_down(int k,int l,int r)
{if(tag[k]){int mid=(l+r)>>1;tag[k<<1]+=tag[k];tag[k<<1|1]+=tag[k];tr[k<<1]+=(mid-l+1)*tag[k];tr[k<<1|1]+=(r-mid)*tag[k];tag[k]=0;}
}
void add(int k,int l,int r,int q,int p,int d)
{if(q<=l&&p>=r){tag[k]+=d;tr[k]+=(r-l+1)*d;return;}push_down(k,l,r);int mid=(l+r)>>1;if(mid>=q){add(k<<1,l,mid,q,p,d);}if(mid<p){add(k<<1|1,mid+1,r,q,p,d);}tr[k]=(tr[k<<1]+tr[k<<1|1]);
}
int query(int k,int l,int r,int q,int p)
{if(q<=l&&p>=r){return tr[k];}push_down(k,l,r);int mid=(l+r)>>1,ssum=0;if(mid>=q){ssum+=query(k<<1,l,mid,q,p);}if(mid<p){ssum+=query(k<<1|1,mid+1,r,q,p);}return ssum;
}
int getsum1(int x,int y)
{int sum=0;while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]]){swap(x,y);}sum=sum+query(1,1,n,id[top[x]],id[x]);x=fa[top[x]];}if(deep[x]>deep[y]){swap(x,y);}sum+=query(1,1,n,id[x],id[y]);return sum;
}
int getsum2(int x)
{return query(1,1,n,id[x],id[x]+si[x]-1);
}
void addsum1(int x,int y,int z)
{while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]]){swap(x,y);}add(1,1,n,id[top[x]],id[x],z);x=fa[top[x]];}if(deep[x]>deep[y]){swap(x,y);}add(1,1,n,id[x],id[y],z);
}
void addsum2(int x,int y)
{add(1,1,n,id[x],id[x]+si[x]-1,y);
}
signed main()
{scanf("%lld%lld%lld%lld",&n,&m,&r,&mod);for(int i=1;i<=n;i++){scanf("%lld",&w[i]);}for(int i=1;i<n;i++){int x,y;scanf("%lld%lld",&x,&y);a[x].push_back(y);a[y].push_back(x);}dfs1(r);dfs2(r,r);build(1,1,n);while(m--){int op;scanf("%lld",&op);if(op==1){int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);addsum1(x,y,z);}if(op==2){int x,y;scanf("%lld%lld",&x,&y);printf("%lld\n",getsum1(x,y)%mod);}if(op==3){int x,y;scanf("%lld%lld",&x,&y);addsum2(x,y);}if(op==4){int x;scanf("%lld",&x);printf("%lld\n",getsum2(x)%mod);}}return 0;
}

相关文章:

树链剖分(重链剖分)

树链剖分的核心思想就是将一棵树剖分成一条一条的链 因为树不好处理 但链比较好处理 为了学会它 我们先要学会树上dfs&#xff08;深度优先搜索&#xff09; 然后就没了&#xff08;雾&#xff09; Because 树链剖分需要用到两个dfs 哦对了 我们还要了解以下的知识点 1.子…...

幻读是什么?用什么隔离级别可以防止幻读?

幻读是什么&#xff1f; 幻读&#xff08;Phantom Read&#xff09; 是数据库事务中的一种现象&#xff0c;指的是在一个事务中&#xff0c;当执行两次相同的查询时&#xff0c;第二次查询返回的结果集包含了第一次查询中不存在的行&#xff0c;或者第一次查询中存在的行在第二…...

[Unity Demo]从零开始制作空洞骑士Hollow Knight第二十集:制作专门渲染HUD的相机HUD Camera和画布HUD Canvas

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、制作HUD Camera以及让两个相机同时渲染屏幕二、制作HUD Canvas 1.制作法力条Soul Orb引入库2.制作生命条Health读入数据3.制作吉欧统计数Geo Counter4.制作…...

智能安全配电装置在高校实验室中的应用

​ 摘要&#xff1a;高校实验室是科研人员进行科学研究和实验的场所&#xff0c;通常会涉及到大量的仪器设备和电气设备。电气设备的使用不当或者维护不周可能会引发火灾事故。本文将以一起实验室电气火灾事故为例&#xff0c;对事故原因、危害程度以及防范措施进行分析和总结…...

网络安全等级保护测评机构管理办法(全文)

网络安全等级保护测评机构管理办法(公信安〔2018〕765号) 第一章 总则 第一条 为加强网络安全等级保护测评机构&#xff08;以下简称“测评机构”&#xff09;管理&#xff0c;规范测评行为&#xff0c;提高等级测评能力和服务水平&#xff0c;根据《中华人民共和国网络安全法…...

Flutter:shared_preferences数据存储,数据持久化,token等信息存储

官方示例&#xff1a;简单调用 // 初始化示例 final SharedPreferences prefs await SharedPreferences.getInstance(); // 存int await prefs.setInt(counter, 10); // 存bool await prefs.setBool(repeat, true); // 存double await prefs.setDouble(decimal, 1.5); // 存st…...

FileProvider高版本使用,跨进程传输文件

高版本的android对文件权限的管控抓的很严格,理论上两个应用之间的文件传递现在都应该是用FileProvider去实现,这篇博客来一起了解下它的实现原理。 首先我们要明确一点,FileProvider就是一个ContentProvider,所以需要在AndroidManifest.xml里面对它进行声明: <provideran…...

python学习记录18

1 函数的定义 python中的函数指使用某个定义好的名字指代一段完整的代码&#xff0c;在使用名字时可以直接调用整个代码&#xff0c;这个名字叫做函数名。利用函数可以达到编写一次即可多次调用的操作&#xff0c;从而减少代码量。 函数分为内置函数与自定义函数。内置函数例…...

云原生之k8s服务管理

文章目录 服务管理Service服务原理ClusterIP服务 对外发布应用服务类型NodePort服务Ingress安装配置Ingress规则 Dashboard概述 认证和授权ServiceAccount用户概述创建ServiceAccount 权限管理角色与授权 服务管理 Service 服务原理 容器化带来的问题 自动调度&#xff1a;…...

redis工程实战介绍(含面试题)

文章目录 redis单线程VS多线程面试题**redis是多线程还是单线程,为什么是单线程****聊聊redis的多线程特性和IO多路复用****io多路复用模型****redis如此快的原因** BigKey大批量插入数据测试数据key面试题海量数据里查询某一固定前缀的key如果生产上限值keys * &#xff0c;fl…...

再次讨论下孤注一掷

在孤注一掷中的黑客技术里面&#xff0c;简单介绍了电影孤注一掷中用的一些"黑科技"&#xff0c;这里继续讨论下&#xff0c;抛弃这些黑科技&#xff0c;即使在绝对公平的情况下&#xff0c;你也一样赢不了赌场 相对论有一个假设就是光速不变&#xff0c;这里也有个…...

LeetCode46.全排列

LeetCode刷题记录 文章目录 &#x1f4dc;题目描述&#x1f4a1;解题思路⌨C代码 &#x1f4dc;题目描述 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例1 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,…...

蓝桥杯-洛谷刷题-day4(C++)

目录 1.高精度乘法 i.P1303 A*B Problem高精度乘法 2.P4924 [1007] 魔法少女小Scarlet i.题目 ii.代码 3.二维数组 i.二维数组的建立 ii.备份 iii.二维数组的转动 4.指令的及时处理 1.高精度乘法 即&#xff0c;将每一位变为数组中的一位&#xff0c;并在数组中以倒序排列&a…...

c++总复习

1. C 中的移动语义及其作用 定义 移动语义是 C 11 引入的一种重要特性&#xff0c;它用于优化对象的资源管理&#xff0c;特别是在涉及对象所有权转移的场景中。传统的 C 语义在对象赋值或传递给函数时&#xff0c;通常会进行拷贝操作&#xff0c;即创建源对象的一个完整副本&…...

设计模式之策略模式-工作实战总结与实现

文章目录 应用场景存在问题解决方案继续延伸 应用场景 假设有这样的业务场景&#xff0c;大数据系统把文件推送过来&#xff0c;根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码&#xff1a; public class Question {public static void main(String[] args…...

E - 11/22 Subsequence题解

文章目录 大致思路代码 大致思路 预处理: 用pos1, pos2, posls 分别记录 1 1 1, 2 2 2 , / / / 在字符串中的『位置』 用cum1 和 cum2 分别存储了 1 1 1 和 2 2 2 的前缀和&#xff0c;这样可以快速获取任意区间内的 1 1 1 和 2 2 2 的『数量』 查询处理: 对于每个查询…...

PyPI 攻击:ChatGPT、Claude 模仿者通过 Python 库传播 JarkaStealer

《Java代码审计》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484219&idx1&sn73564e316a4c9794019f15dd6b3ba9f6&chksmc0e47a67f793f371e9f6a4fbc06e7929cb1480b7320fae34c32563307df3a28aca49d1a4addd&scene21#wechat_redirect 《Web安全》h…...

单片机学习笔记 9. 8×8LED点阵屏

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…...

【大模型-智能体】AutoGen Studio测试和导出工作流程

1. 测试工作流程 AutoGen Studio允许用户针对任务交互式地测试工作流程&#xff0c;并审查由此产生的成果物&#xff08;如图像、代码和文档&#xff09;。此外用户还可以查看Agent工作流程在处理任务时的“内心独白”&#xff0c;并查看诸如运行成本&#xff08;如回合数、令牌…...

【Linux】-学习笔记04

第十二章、磁盘管理 1.查看磁盘空间使用量 1.1df命令 作用&#xff1a; 列出文件系统的磁盘空间占用情况 df&#xff0c;disk free&#xff0c;通过文件系统来快速获取空间大小的信息&#xff0c;当我们删除一个文件的时候&#xff0c;这个文件 不是马上就在文件系统当中消…...

【教程】全流程基于最新导则下的生态环境影响评价技术方法及图件制作与案例实践技术应用

专题一&#xff1a;生态环境影响评价框架及流程 以某既包含陆域、又包含水域的项目为主要案例&#xff0c;兼顾其它类型项目&#xff0c;主要内容包括&#xff1a; 1、生态环境影响评价基本思路与要求&#xff1a;工作程序、报告编制技术要求与规范 2、资料收集与初步踏勘&a…...

阅读落地灯哪个牌子好?优质款阅读落地灯推荐,买前建议收藏!

​想要真正舒服又省心的照明&#xff0c;就别只会盯着参数看。说实话&#xff0c;挑护眼大路灯我就盯两点&#xff1a;光线柔不柔、用久了会不会累眼。像我家书桌前那种容易眩光的&#xff0c;我用一会儿就觉得不对劲&#xff1b;但像下面这些护眼大路灯&#xff0c;调光调色做…...

小学期第一周

理论部分&#xff1a;学会了低通滤波器原理&#xff1a;只允许低于截止频率的信号通过&#xff0c;高于截止频率的信号被大幅衰减方波变成正弦波的原理&#xff1a;方波是基波无数奇次谐波的叠加&#xff0c;低通滤波器只留基波、滤掉高频谐波&#xff0c;输出就接近正弦波二阶…...

网页端嵌入 Agent 对接前端方案

本文将深入探讨「网页端嵌入AI」的核心概念与实战技巧&#xff0c;帮助你快速掌握关键要点。让我们开始吧&#xff01; 网页端嵌入 Agent 对接前端方案 1. 引言 当前前端项目正从被动展示走向主动交互&#xff0c;AI Agent 嵌入网页端可自动化 UI 操作、优化布局并辅助编码。…...

如何通过纯JavaScript拖拽构建器实现零代码网站开发

如何通过纯JavaScript拖拽构建器实现零代码网站开发 【免费下载链接】VvvebJs Drag and drop page builder library written in vanilla javascript without dependencies or build tools. 项目地址: https://gitcode.com/gh_mirrors/vv/VvvebJs 在网站开发领域&#xf…...

2026年福建莆田大平层全屋高端定制选型指南

一、引言福建莆田近年来经济发展迅速&#xff0c;居民生活水平不断提高&#xff0c;大平层住宅逐渐成为高端改善型住房的热门选择。在全屋高端定制方面&#xff0c;消费者面临着众多品牌的选择。本指南旨在为莆田的大平层业主提供一份合规、靠谱且适配自身需求的高端定制品牌选…...

程序员需求攀升:数字化浪潮下的行业必然

在数字经济深度渗透的今天&#xff0c;软件开发行业正经历着前所未有的扩张期&#xff0c;程序员岗位需求的持续攀升成为行业发展的鲜明特征。作为与开发环节紧密联动的测试从业者&#xff0c;深入理解这一现象背后的逻辑&#xff0c;不仅能帮助我们把握行业趋势&#xff0c;更…...

Java智能地址解析架构深度解析:构建高精度企业级地址识别系统

Java智能地址解析架构深度解析&#xff1a;构建高精度企业级地址识别系统 【免费下载链接】address-parse Java 版智能解析收货地址 项目地址: https://gitcode.com/gh_mirrors/addr/address-parse 面对海量非结构化地址数据的处理挑战&#xff0c;传统规则引擎已无法满…...

MC端口映射完全教程:路由器虚拟服务器配置+防火墙放行+内网穿透备用方案

一、什么是MC端口映射MC端口映射是指将运行《我的世界》服务器的电脑内网IP和端口&#xff08;Java版默认25565&#xff09;&#xff0c;通过路由器设置“映射”到公网&#xff0c;让外网玩家能够连接进来。简单说&#xff0c;就是把你自己电脑上开的游戏房“门牌号”告诉全世界…...

告别小屏幕!5个专业技巧让你在Windows大屏上高效刷酷安

告别小屏幕&#xff01;5个专业技巧让你在Windows大屏上高效刷酷安 【免费下载链接】Coolapk-UWP 一个基于 UWP 平台的第三方酷安客户端 项目地址: https://gitcode.com/gh_mirrors/co/Coolapk-UWP 还在忍受手机小屏幕刷酷安的酸涩感吗&#xff1f;想象一下&#xff0c;…...