树链剖分及其应用

基本概念:

1.重儿子:假设节点u有n个子结点,其中以v子节点的为根子树的大小最大,那么v就是u的重儿子

2.轻儿子:除了重儿子以外的全部儿子都是轻儿子

3.轻边:结点u与轻儿子连接的边

4.重边:结点u与重儿子连接的边

5.轻链:均由轻儿子组成的一条链

6.重链:均由重儿子组成的一条链

预处理节点信息:

dep[u]:u节点的深度

fa[u]:u结点的父亲结点

son[u]:u结点的重儿子

siz[u]:以u节点为根的子树的大小

top[u]:u结点所在的链的顶点

首先,我们可以很简单地通过dfs获取一个结点的dep,fa和siz,从而也就获得了siz

实现代码如下:

#include <iostream>
using namespace std;
const int N = 2E5 + 10;
int dep[N], fa[N], son[N], siz[N], top[N];
int to[N << 1], nxt[N << 1], h[N], tot;
void dfs1(int u,int f){siz[u] = 1;dep[u] = dep[f] + 1;fa[u] = f;int max = 0;for (int i = h[u], v; v = to[i];i=nxt[i]){if(v==f){continue;}dfs1(v, u);siz[u] += siz[v];if(siz[v]>max){max = siz[v];son[u] = v;}}
}

接下来,我们再用一个dfs来获取top数组

处理的方式为:

重儿子的top就等于自己u节点的top

轻儿子的top就等于轻儿子本身

实现代码如下:

void dfs2(int u,int f){for (int i = h[u], v; v = to[i];i=nxt[i]){if(v==f){continue;}if(v==son[u]){top[v] = top[u];}else{top[v] = v;}dfs2(v, u);}
}

树链剖分的应用:

1.寻找最近公共祖先(lca)

对于两个结点x和y

假设他们在同一条链上,也就是top相同,那么他们的lca就是深度比较小的一方

如果他们不在同一条链上

我们知道,他们肯定可以通过若干条链走到同一条链上

如何将一个结点从一条链转移到另一条链呢?

只需要让top[u]的深度较大的一方跳到其top[u]的父亲结点上,自然就到了另一条新链了

而且可以保证他们两个的top越来越接近,直到top相同

实现代码如下:

int lca(int x,int y){while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]){swap(x, y);}x = fa [top [x]];}return dep[x] < dep[y] ? x : y;
}

2.维护树上区间

我们轻重链剖分以后,每条链都是一个连续的区间

如果想要对路径(x,y)做区间修改和区间查询的操作

只需要对组成这条路径的若干条树链进行维护即可

具体操作为:

在跳跃到x与y在共同链之前

我们对区间dfn[top[x]]到dfn[x]进行修改,查询

维护区间的数据结构我们选择使用线段树

题目链接:P3384 【模板】重链剖分/树链剖分 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

实现代码如下(码了一个小时,找bug找了一个小时,还是对线段树不是很熟练):

#include <iostream>
using namespace std;
const int N = 1E5 + 10;
#define ll long long
#define ls (i << 1)
#define rs (i << 1 | 1)
#define mid (left + right >> 1)
int to[N << 1], nxt[N << 1], h[N], tot;
int dfn[N], siz[N], son[N], top[N], dep[N], fa[N], idx;
// dfn[u],轻重链u结点的dfs序(区间序号)
// v[u],u结点的点权
// a[i],区间下标i的点权
int a[N], v[N];
int n, m, s;
long long mod;
// 加边
void add(int a, int b)
{to[++tot] = b;nxt[tot] = h[a];h[a] = tot;
}
// 获取每个结点的根树的size,获取深度dep,获取儿子son
void dfs1(int u, int f)
{dep[u] = dep[f] + 1;siz[u] = 1;fa[u] = f;int max = 0;for (int i = h[u], v; v = to[i]; i = nxt[i]){if (v == f){continue;}dfs1(v, u);if (siz[v] > max){max = siz[v];son[u] = v;}siz[u] += siz[v];}
}
// 获取dfn序和top
void dfs2(int u, int f)
{dfn[u] = ++idx;a[idx] = v[u];if (son[u]){top[son[u]] = top[u];dfs2(son[u], u);}for (int i = h[u], v; v = to[i]; i = nxt[i]){if (v == f || v == son[u]){continue;}top[v] = v;dfs2(v, u);}
}
//线段树
struct node
{int l, r;ll sum;ll tag;
} tr[4 * N];
void pushup(int i)
{tr[i].sum = (tr[ls].sum + tr[rs].sum) % mod;
}
void pushdown(int i)
{if (tr[i].l != tr[i].r && tr[i].tag){tr[ls].sum = (tr[ls].sum + ((tr[ls].r-tr[ls].l+1)%mod*tr[i].tag)) % mod;tr[rs].sum = (tr[rs].sum + ((tr[rs].r-tr[rs].l+1)*tr[i].tag)) % mod;tr[rs].tag = (tr[i].tag+tr[rs].tag)%mod;tr[ls].tag = (tr[i].tag+tr[ls].tag)%mod;tr[i].tag = 0;}
}
// 建树
void build(int i, int left, int right)
{tr[i].l = left;tr[i].r = right;if (left == right){tr[i].sum = a[left];return;}build(ls, left, mid);build(rs, mid + 1, right);pushup(i);
}
void add(int i, ll k, int left, int right)
{if (tr[i].l >= left && tr[i].r <= right){tr[i].sum = (((tr[i].r - tr[i].l + 1) % mod * k) % mod + tr[i].sum) % mod;tr[i].tag = (k + tr[i].tag) % mod;return;}int mmid = (tr[i].l + tr[i].r >> 1);pushdown(i);if (right >= mmid + 1){add(rs, k, left, right);}if (left <= mmid){add(ls, k, left, right);}pushup(i);
}
ll search(int i, int left, int right)
{if (tr[i].l >= left && tr[i].r <= right){return tr[i].sum;}pushdown(i);ll res = 0;int mmid = (tr[i].l + tr[i].r >> 1);if (right >= mmid + 1){res += search(rs, left, right);}if (left <= mmid){res = (res + search(ls, left, right)) % mod;}return res;
}
int main()
{cin >> n >> m >> s >> mod;for (int i = 1; i <= n; i++){cin >> v[i];v[i] %= mod;}for (int i = 1, x, y; i < n; i++){cin >> x >> y;add(x, y);add(y, x);}dfs1(s, 0);top[s] = s;dfs2(s, 0);build(1, 1, n);ll z;int l, r;ll ans;for (int i = 1, opt, x, y; i <= m; i++){cin >> opt;if (opt == 1){cin >> x >> y >> z;while (top[x] != top[y]){if (dep[top[x]] < dep[top[y]]){swap(x, y);}add(1, z, dfn[top[x]], dfn[x]);x = fa[top[x]];}if (dep[x] < dep[y]){l = dfn[x];r = dfn[y];}else{l = dfn[y];r = dfn[x];}add(1, z, l, r);}else if (opt == 2){cin >> x >> y;ans = 0;while (top[x] != top[y]){if (dep[top[x]] < dep[top[y]]){swap(x, y);}ans = (ans + search(1, dfn[top[x]], dfn[x])) % mod;x = fa[top[x]];}if (dep[x] < dep[y]){l = dfn[x];r = dfn[y];}else{l = dfn[y];r = dfn[x];}ans = (ans + search(1, l, r)) % mod;cout << ans << endl;}else if (opt == 3){cin >> x >> z;add(1, z, dfn[x], dfn[x] + siz[x] - 1);}else if (opt == 4){cin >> x;cout << search(1, dfn[x], dfn[x] + siz[x] - 1) << endl;}}return 0;
}

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

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

相关文章

如何制作自己的网站

制作自己的网站可以帮助个人或组织在互联网上展示自己的品牌、作品、产品或服务。随着技术的发展&#xff0c;现在制作网站变得越来越简单。下面是一个简单的步骤指南&#xff0c;帮助你制作自己的网站。 1. 确定你的网站需求和目标 在开始之前&#xff0c;你需要明确你的网站的…

CSS Grid网格布局

一、前言 二、Grid布局 1、基本介绍 2、核心概念 &#xff08;1&#xff09;网格容器 &#xff08;2&#xff09;网格元素 &#xff08;3&#xff09;网格列 &#xff08;4&#xff09;网格行 &#xff08;5&#xff09;网格间距 &#xff08;6&#xff09;网格线 三…

基于PHP的酒店管理系统(改进版)

有需要请加文章底部Q哦 可远程调试 基于PHP的酒店管理系统(改进版) 一 介绍 此酒店管理系统(改进版)基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端jquery插件美化。系统角色分为用户和管理员。系统在原有基础上增加了注册登录注销功能&#xff0c;增加预订房间图片…

Spring Boot中如何集成GraphQL

Spring Boot中如何集成GraphQL 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Spring Boot应用中集成GraphQL&#xff0c;这是一种强大的查…

Claude走向开放

Claude的愿景一直是创建能够与人们协同工作并显著提升他们工作流程的人工智能系统。朝着这一方向迈进&#xff0c;Claude.ai的专业版和团队版用户现在可以将他们的聊天组织到项目中&#xff0c;将精选的知识和聊天活动整合到一个地方&#xff0c;并且可以让团队成员查看他们与C…

DLMS/COSEM协议—(Green-Book)Wi-SUN profile

10.9 Wi-SUN profile&#xff08;Wireless Smart Utility Network&#xff09; 10.9.1 概述 (General) Wi-SUN FAN&#xff08;Field Area Network&#xff0c;现场区域网络&#xff09;旨在构建一个无处不在的网络&#xff0c;但它并没有指定特定的应用来在其上运行&#xf…

什么是期货基金?

期货基金&#xff0c;是指广大投资者将资金集中起来&#xff0c;委托给专业的期货投资机构&#xff0c;并通过商品交易顾问进行期货投资交易&#xff0c;投资者承担投资风险并享有投资利润的一种集合投资方式。期货基金的投资对象主要有两大类商品&#xff1a;期货与金融期货。…

django学习入门系列之第三点《案例 商品推荐部分》

文章目录 划分区域搭建骨架完整代码小结往期回顾 划分区域 搭建骨架 /*商品图片&#xff0c;父级设置*/ .slider .sd-img{display: block;width: 1226px;height: 460px; }<!-- 商品推荐部分 --> <!--搭建出一个骨架--> <div class"slider"><di…

提高开发效率之——工具介绍

一 . SerialDebug 串口调试工具 SerialDebug 是一个串口调试工具&#xff0c;它主要用于帮助电子工程师和软件开发者进行串口通信的调试工作。以下是 SerialDebug 工具的一些主要作用和特点: 基础串口通信功能&#xff1a;提供打开、关闭、接收、发送数据的基础串口操作。 数…

.NET C# 使用OpenCV实现人脸识别

.NET C# 使用OpenCV实现模型训练、人脸识别 码图~~~ 1 引入依赖 OpenCvSHarp4 - 4.10.0.20240616 OpenCvSHarp4.runtime.win - 4.10.0.20240616 2 人脸数据存储结构 runtime directory | face | {id}_{name} | *.jpg id - 不可重复 name - 人名 *.jpg - 人脸照片3 Demo 3.…

7.javaSE基础_进阶:反射机制(Method,Filed,Constructor,Properties)

文章目录 一.反射1.定义2.功能3.应用4.常用类和API5.Class类5.Class实例方式 二.相关类及API1.Method类1)invoke方法 2.Field类1)给属性赋值 3.Constructor类 三.Proterties1.定义**2.Properties特点&#xff1a;**3.properties配置文件作用4.常用方法5.Java读取Properties文件…

前置章节-熟悉Python、Numpy、SciPy和matplotlib

目录 一、编程环境-使用jupyter notebook 1.下载homebrew包管理工具 2.安装Python环境 3.安装jupyter 4.下载Anaconda使用conda 5.使用conda设置虚拟环境 二、学习Python基础 1.快排的Python实现 (1)列表推导-一种创建列表的简洁方式 (2)列表相加 2.基本数据类型及运…

FastGPT 调用Qwen 测试Hello world

Ubuntu 安装Qwen/FastGPT_fastgpt message: core.chat.chat api is error or u-CSDN博客 参考上面文档 安装FastGPT后 登录&#xff0c; 点击右上角的 新建 点击 这里&#xff0c;配置AI使用本地 ollama跑的qwen模型 问题&#xff1a;树上有3只鸟&#xff0c;开了一枪&#…

实战STM32:硬件SPI与模拟SPI读写W25Q64存储芯片

摘要 本文是一篇实战教程&#xff0c;指导读者如何在STM32微控制器上通过硬件SPI和模拟SPI实现对W25Q64存储芯片的读写操作。W25Q64是一款8Mbit的SPI Flash存储器&#xff0c;适用于需要非易失性存储的嵌入式系统。本文将深入讲解硬件连接、SPI配置、读写流程&#xff0c;并提…

使用CDN方式创建Vue3.0应用程序

CDN 的全称是 content delivery network&#xff0c;即内容分发网络。它是构建在现在的互联网基础之上的一层智能虚拟网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分发和调度等功能模块&#xff0c;使用户就近获取所需内容&#xff0c…

matlab量子纠缠态以及量子门操作下的量子态

前言 今天我们来聊聊题外话&#xff0c;量子纠缠&#xff0c;在目前物理分支中&#xff0c;要说最深&#xff0c;最能改变人类对宇宙影响的莫过于量子力学了&#xff0c;假如我们可以人为的对两个粒子施加纠缠态&#xff0c;那么我们将可以足不出户的完成对外界的操控 简介 …

《TopFormer: Token Pyramid Transformer for Mobile Semantic Segmentation》

期刊&#xff1a;CVPR 年份&#xff1a;2022 代码&#xff1a;https://github.com/hustvl/TopFormer 摘要 尽管视觉Transformer(ViTs)在计算机视觉领域取得了巨大的成功&#xff0c;但沉重的计算成本阻碍了它们在密集预测任务中的应用&#xff0c;如移动设备上的语义分割。…

Superagent:一个开源的AI助手框架与API

在人工智能日益普及的今天,如何将AI助手无缝集成到应用中成为了开发者们关注的焦点。今天,我们要介绍的Superagent正是一个为这一需求量身打造的开源框架与API。它结合了LLM、检索增强生成(RAG)和生成式AI技术,为开发者们提供了一个强大而灵活的解决方案。 一、Superagen…

电阻屏和电容屏

目录 一、电阻屏 1.欧姆定律 2.电阻屏原理 &#xff08;1&#xff09;测量 X 坐标 &#xff08;2&#xff09;测量 Y 坐标 3.电阻屏数据 二、电阻屏 1.原理 2.电容屏数据 &#xff08;1&#xff09;Type A &#xff08;2&#xff09;Type B 3.电容屏的实验数据 一、…

C# Socket

Socket命名空间&#xff1a;创建 Socket&#xff1a;连接到服务器&#xff08;客户端&#xff09;&#xff1a;绑定和监听&#xff08;服务器端&#xff09;&#xff1a;接受连接&#xff08;服务器端&#xff09;&#xff1a;发送和接收数据&#xff1a;关闭 Socket&#xff1…