树链剖分(重链剖分)
树链剖分的核心思想就是将一棵树剖分成一条一条的链
因为树不好处理 但链比较好处理
为了学会它 我们先要学会树上dfs(深度优先搜索) 然后就没了(雾)
Because 树链剖分需要用到两个dfs
哦对了 我们还要了解以下的知识点
1.子树大小
就是一个节点的子树的节点个数(包括它自己)
2.重儿子
一个节点的所有儿子中子树大小最大的儿子
3.轻儿子
除了重儿子之外的儿子(包括根节点)
4.重边
两个相邻的重儿子连成的边
5.重链
重边连成的链(开头是轻儿子)
OK,了解完了
启动!
dfs1:
目标是求出以下数据
1: 节点的父节点
2: 节点的深度 也就是它到根节点的距离
3: 节点的重儿子
4: 节点的子树大小
思路十分的简单 直接上代码
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: 节点的所在的重链的顶端节点
2: 节点的新编号
3: 节点的新编号的值
其中 新编号的原则是先走重儿子 再走轻儿子(理由下次一定)
比如
懂了吗? 我相信你肯定懂了
思路也十分的简单 直接上代码
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
通过观察图片可以看出
一个节点的子树的编号肯定是连续的
设子树的根是
左端点是的编号是 右端点的编号是
所以3操作就是将到
加上
4操作就是求出到
的值的和
即区间修改 ,区间查询
我们当然会想到线段树啦
直接拿下
之后我们来看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(深度优先搜索) 然后就没了(雾) Because 树链剖分需要用到两个dfs 哦对了 我们还要了解以下的知识点 1.子…...

幻读是什么?用什么隔离级别可以防止幻读?
幻读是什么? 幻读(Phantom Read) 是数据库事务中的一种现象,指的是在一个事务中,当执行两次相同的查询时,第二次查询返回的结果集包含了第一次查询中不存在的行,或者第一次查询中存在的行在第二…...

[Unity Demo]从零开始制作空洞骑士Hollow Knight第二十集:制作专门渲染HUD的相机HUD Camera和画布HUD Canvas
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、制作HUD Camera以及让两个相机同时渲染屏幕二、制作HUD Canvas 1.制作法力条Soul Orb引入库2.制作生命条Health读入数据3.制作吉欧统计数Geo Counter4.制作…...

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

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

Flutter:shared_preferences数据存储,数据持久化,token等信息存储
官方示例:简单调用 // 初始化示例 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中的函数指使用某个定义好的名字指代一段完整的代码,在使用名字时可以直接调用整个代码,这个名字叫做函数名。利用函数可以达到编写一次即可多次调用的操作,从而减少代码量。 函数分为内置函数与自定义函数。内置函数例…...

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

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

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

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

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

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

设计模式之策略模式-工作实战总结与实现
文章目录 应用场景存在问题解决方案继续延伸 应用场景 假设有这样的业务场景,大数据系统把文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码: 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 的前缀和,这样可以快速获取任意区间内的 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点阵屏
更多单片机学习笔记:单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…...

【大模型-智能体】AutoGen Studio测试和导出工作流程
1. 测试工作流程 AutoGen Studio允许用户针对任务交互式地测试工作流程,并审查由此产生的成果物(如图像、代码和文档)。此外用户还可以查看Agent工作流程在处理任务时的“内心独白”,并查看诸如运行成本(如回合数、令牌…...

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

计算机网络:应用层知识点概述及习题
网课资源: 湖科大教书匠 1、概述 习题1 1 在计算机网络体系结构中,应用层的主要功能是 A. 实现进程之间基于网络的通信 B. 通过进程之间的交互来实现特定网络应用 C. 实现分组在多个网络上传输 D. 透明传输比特流 2 以下不属于TCP/IP体系结构应用层范畴…...

如何构建高效的接口自动化测试框架?
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 在选择接口测试自动化框架时,需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说,使用Python相关的测试框架更为便捷。无论选…...

【C++习题】10.反转字符串中的单词 lll
题目: 链接🔗:557.反转字符串中的单词 lll 题目: 代码: class Solution { public:void Reverse(string &s, int start, int end){char tmp;while(start < end){tmp s[start];s[start] s[end];s[end] tmp;…...

undefined symbol: __nvJitLinkComplete_12_4, version libnvJitLink.so.12 问题解决
在部署运行opencompass项目时遇到了如下报错: ImportError: /data/conda/envs/opencompass/lib/python3.10/site-packages/torch/lib/../../nvidia/cusparse/lib/libcusparse.so.12: undefined symbol: __nvJitLinkComplete_12_4, version libnvJitLink.so.12…...

C语言——数组逐元素操作练习
定义一个能容纳10个元素的整形数组a,从键盘读取9个整数存放到前9个数组元素中。 一. 从键盘读取一个整数n和位置p(0<p<8),插入n到数组a中,插入位置:下标p。要求插入点及后续的数组元素都要后移动。 代码如下: …...

HTML的自动定义倒计时,这个配色存一下
<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>自定义倒计时</title><style>* {mar…...

CUDA补充笔记
文章目录 一、不同核函数前缀二、指定kernel要执行的线程数量三、线程需要两个内置坐标变量来唯一标识线程四、不是blocksize越大越好,上限一般是1024个blocksize 一、不同核函数前缀 二、指定kernel要执行的线程数量 总共需要线程数是: 1 * N N个线程…...

C++二级:满足条件的数的累加
现有n个整数,将其中个位数为k的数进行累加求和。 输入 第一行1个整数n。( 0 < n < 1000) 第二行n个非负整数,以空格分隔,每个数不大于100000。 第三行1个整数k。(0 ≤ k ≤ 9) 输出 输出满足题目要求的累加和。…...

【山大909算法题】2014-T1
文章目录 1.原题2.算法思想3.关键代码4.完整代码5.运行结果 1.原题 为带表头的单链表类Chain编写一个成员函数Reverse,该函数对链表进行逆序操作(将链表中的结点按与原序相反的顺序连接),要求逆序操作就地进行,不分配…...

【MySQL实战45讲笔记】基础篇——深入浅出索引(上)
系列文章 基础篇——MySQL 的基础架构 基础篇——redo log 和 binlog 基础篇——事务隔离 目录 系列文章深入浅出索引(上)4.1 索引的常见模型4.2 InnoDB 的索引模型4.3 索引维护4.4 思考:为什么要重建索引以及如何做? 深入浅出索…...