洛谷题单指南-图论之树-P3128 [USACO15DEC] Max Flow P

news/2025/3/6 14:47:29/文章来源:https://www.cnblogs.com/jcwy/p/18754359

原题链接:https://www.luogu.com.cn/problem/P3128

题意解读:一棵树,每次选取两个节点,在这两个节点之间路径运送牛奶,每运送一次,经过的所有节点都会增加1,最终统计记录最大的节点。

解题思路:

要计算树上两个节点之间的路径,可以采用LCA算法,确定路径之后如果将路径中所有点都加1呢?

1、暴力法

直接枚举,加1,复杂度O(n),一共要操作k次,总体复杂度O(nlogn + kn)

2、树上差分

借助于树上差分操作,可以O(1)复杂度对要路径上的点进行+1操作,最后还原前缀和数组就是每个节点运送牛奶的次数,总体复杂度O(nlogn+k+n)

树上差分详解

树上差分是一种用于处理树上路径问题的高效算法技巧,其核心思想与序列上的差分类似。在序列上,差分是通过记录相邻元素的差值来简化区间修改和单点查询操作;而在树上,树上差分则是利用树的结构特点,通过对树上某些节点的标记来实现对树上路径的修改和查询,最终通过一次深度优先搜索(DFS)将标记信息传递到整棵树,从而高效地统计路径上的信息。
树上差分主要分为两种类型:边差分和点差分,下面分别进行介绍。

边差分

边差分用于处理树上路径边的修改问题。对于树上的一条路径u-v ,我们需要对这条路径上的所有边进行某种修改(例如增加某个值),可以通过在路径两端点u和v以及它们的最近公共祖先lca(u,v)处进行标记,然后通过一次 DFS 计算出每条边的实际修改值。

点差分

点差分用于处理树上路径点的修改问题。对于树上的一条路径u-v,我们需要对这条路径上的所有点进行某种修改(例如增加某个值),同样可以在路径两端点u和v以及它们的最近公共祖先lca(u,v)处进行标记,不同的是点差分还需要对lca(u,v)的父节点进行额外标记,最后通过一次 DFS 计算出每个点的实际修改值

示例代码

#include <iostream>
#include <vector>
using namespace std;const int MAXN = 100005;
vector<int> adj[MAXN];  // 邻接表存储树的结构
int depth[MAXN];        // 存储每个节点的深度
int parent[MAXN][20];   // 用于求 LCA,parent[u][i] 表示节点 u 的 2^i 级祖先
int diff_edge[MAXN];    // 边差分标记数组
int diff_point[MAXN];   // 点差分标记数组// 深度优先搜索,计算每个节点的深度和父节点
void dfs(int u, int p, int d) {depth[u] = d;parent[u][0] = p;for (int i = 1; i < 20; i++) {parent[u][i] = parent[parent[u][i - 1]][i - 1];}for (int v : adj[u]) {if (v != p) {dfs(v, u, d + 1);}}
}// 求两个节点的最近公共祖先
int lca(int u, int v) {if (depth[u] < depth[v]) swap(u, v);for (int i = 19; i >= 0; i--) {if (depth[u] - (1 << i) >= depth[v]) {u = parent[u][i];}}if (u == v) return u;for (int i = 19; i >= 0; i--) {if (parent[u][i] != parent[v][i]) {u = parent[u][i];v = parent[v][i];}}return parent[u][0];
}// 边差分操作,对路径 u - v 上的边进行修改
void edge_diff(int u, int v, int val) {int l = lca(u, v);diff_edge[u] += val;diff_edge[v] += val;diff_edge[l] -= 2 * val;
}// 点差分操作,对路径 u - v 上的点进行修改
void point_diff(int u, int v, int val) {int l = lca(u, v);diff_point[u] += val;diff_point[v] += val;diff_point[l] -= val;if (parent[l][0] != -1) {diff_point[parent[l][0]] -= val;}
}// 深度优先搜索,计算边差分的结果
void dfs_edge(int u, int p) {for (int v : adj[u]) {if (v != p) {dfs_edge(v, u);diff_edge[u] += diff_edge[v];}}
}// 深度优先搜索,计算点差分的结果
void dfs_point(int u, int p) {for (int v : adj[u]) {if (v != p) {dfs_point(v, u);diff_point[u] += diff_point[v];}}
}int main() {int n;  // 节点数量cin >> n;for (int i = 0; i < n - 1; i++) {int u, v;cin >> u >> v;adj[u].push_back(v);adj[v].push_back(u);}// 初始化根节点的父节点为 -1dfs(1, -1, 0);int q;  // 查询数量cin >> q;while (q--) {int u, v, val;cin >> u >> v >> val;// 边差分操作edge_diff(u, v, val);// 点差分操作point_diff(u, v, val);}// 计算边差分的结果dfs_edge(1, -1);// 计算点差分的结果dfs_point(1, -1);// 输出边差分的结果cout << "边差分结果:" << endl;for (int i = 1; i <= n; i++) {cout << "节点 " << i << " 关联边的修改值: " << diff_edge[i] << endl;}// 输出点差分的结果cout << "点差分结果:" << endl;for (int i = 1; i <= n; i++) {cout << "节点 " << i << " 的修改值: " << diff_point[i] << endl;}return 0;
}

前缀和数组的本质

计算点差分数组的前缀和后得到的前缀和数组,表示每个节点在所有路径修改操作后的实际修改量。在 DFS 过程中,子节点的差分值会累加到其父节点上,最终每个节点的前缀和值就是该节点在所有子树路径修改操作影响下的最终变化值。

例如,在一个需要统计每个节点被经过次数的问题中,我们可以通过点差分对经过的路径上的节点进行标记,然后计算前缀和,这样每个节点的前缀和值就是该节点被经过的总次数。或者在一个节点权值修改的问题中,通过点差分和前缀和计算,我们可以得到每个节点修改后的实际权值。

综上所述,树上差分的差分数组计算出的前缀和数组本质上是对树上路径操作在节点或边上的综合影响结果,它能帮助我们高效地处理树上路径的修改和查询问题。

对于此题,用到点差分即可,下面给出代码。

100分代码:

#include <bits/stdc++.h>
using namespace std;const int N = 50005;
vector<int> g[N];
int depth[N], fa[N][20];
int b[N]; //树上差分数组,本质是对节点值的修改
int s[N]; //树上前缀和数组,本质对子树所有节点值修改的累加
int n, k, ans;void dfs(int u, int parent)
{depth[u] = depth[parent] + 1;fa[u][0] = parent;for(int j = 1; j <= 18; j++)fa[u][j] = fa[fa[u][j - 1]][j - 1];for(auto v : g[u]){if(v == parent) continue;dfs(v, u);}
}int lca(int u, int v)
{if(depth[u] < depth[v]) swap(u, v);for(int j = 18; j >= 0; j--){if(depth[fa[u][j]] >= depth[v])u = fa[u][j];}if(u == v) return u;for(int j = 18; j >= 0; j--){if(fa[u][j] != fa[v][j]){u = fa[u][j];v = fa[v][j];}}return fa[u][0];
}//树上前缀和,节点u的前缀和是节点u的值加上所有子树的前缀和
void sum(int u, int parent)
{s[u] = b[u]; for(auto v : g[u]){if(v == parent) continue;sum(v, u);s[u] += s[v];}ans = max(ans, s[u]);
}int main()
{cin >> n >> k;int u, v;for(int i = 1; i < n; i++){cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs(1, 0);while(k--){cin >> u >> v;int p = lca(u, v);b[u]++;b[v]++;b[p]--;b[fa[p][0]]--;}sum(1, 0);cout << ans;return 0;
}

 

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

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

相关文章

virtualbox下载安装配置

virtualbox下载安装配置 下载 https://www.virtualbox.org/ 官网 https://www.virtualbox.org/wiki/Downloads 官网下载页 https://www.filehorse.com/download-virtualbox/old-versions/ 历史版本推荐使用第三个网址即可,我这里是安装的6.1.26版本 安装 右键安…

奶龙验证app

主要加密逻辑和密文 先encrypt加密 然后进行AES/GCM/NoPadding加密 再使用base64加密 对密文解密为乱码,所以将其转换为hexAES-GCM模式 解密时需要的tag是在加密的过程中产生的 为密文的后2,4,8或16位解密 “{”的ASCII码为123encrypt加密在so层为魔改base64大概可以这么理解…

又一中国团队惊艳全球!Manus开启AI智能新篇章

大家好啊,我是仙生。 本来今天还是分享一些有意思的网站,但是早上醒来看到卡神@数字生命卡兹克又熬夜紧跟AI时事写了一篇文章,好家伙我知道这会AI圈又要爆了。 而果不其然的是,一个上午过去,AI概念股又是狂涨,DeepSeek概念股猛猛涨。 那到底咋回事呢? AI领域又现惊人突破…

使用 CloudDM 和企业微信流程化管理数据库变更审批

CloudDM 是一个专为团队协同工作打造的数据库数据管控平台。在管控数据库安全变更的过程中,为提高效率,方便用户使用,CloudDM 接入了主流 OA 协同办公系统(包括钉钉、飞书、企业微信),支持实时通知与移动办公,满足广大企业用户的实际需求。 本文将介绍如何使用 CloudDM …

从中国到全球:头部HR SaaS厂商易路助力奥佳华全球布局增强国际竞争力

作为中国人力资源SaaS领军企业,易路人力资源科技成立于2004年,20年来坚持面向全球中大型企业,以科技赋能人力资源。易路People+是为中大型企业打造的以薪酬为核心的一站式人力资源软件平台,将全球800万用户的先进管理理念与实践总结融合至标准化的SaaS平台,覆盖企业人力资…

〖大系统 观数智〗: 油气大模型部署应用策略讨论

概述:根据业务层级和专业角色部署规模适当的模型。从基础模型到行业/领域模型,再到各层级和专业模型,按照大系统观全息思维,采取逐级知识蒸馏的策略保持系统的结构完整性、一致性和协作能力,逐级缩小模型规模,同时按需分布式自组织部署,配合本地知识库等,建设全息有机系…

数字钥匙系统BLE/UWB

数字钥匙方案采用蓝牙或BLE+UWB技术实现,简称BLE/UWB。BLE即蓝牙低能耗也称低功耗蓝牙。超宽带技术是一种无线载波通信技术,它是利用纳秒级的非正弦波窄脉冲传输数据。数字钥匙是一项创新的汽车钥匙,可以通过蓝牙/UWB定位算法确认钥匙所在区域。UWB技术也可实现脚踢开行李箱…

2027年100%国产替代真的能实现吗?从金融行业看5大关键突破点

在当今数字化浪潮汹涌澎湃的时代,信息技术应用创新(信创)已成为推动我国经济社会发展的重要引擎。金融行业作为国家经济的核心,其信息化建设对于保障国家金融安全和促进经济发展具有重要意义。2027 年,随着信创产业的深入推进,金融行业有望在国产替代方面取得重大突破。今…

在 Mac 上解决 LM Studio 无法下载模型的问题(国内镜像替换教程)

如果你在使用 LM Studio 时遇到类似 There was an error fetching results from Hugging Face 或 Model details error: fetch failed 的报错,大概率是因为国内网络无法稳定连接 Hugging Face 服务器。配置代理可能也无效,但通过替换 LM Studio 内置的 Hugging Face 域名为其…

向新向智向未来,且看天翼云!

护民生“烟火气”,筑幸福“根基石” 多元的民生需求,化作发展引擎的 “燃料仓” 驱动产业创新求变,开启经济繁荣新篇!产业发展是民生福祉的经济基础 为响应“以科技创新为引领,统筹推进 传统产业升级、新兴产业壮大 未来产业培育”要求 作为云服务国家队 天翼云不断提升科…

当AI开始打工:中国团队研发的Manus让我惊掉下巴

昨天夜里,深夜惊雷。一个新团队突然发了一个首款通用行的项目:Manus。 它就是 Monica.im 研发的全球首款 AI Agent 产品「Manus」。据团队介绍,「Manus」是一个真正自主的 AI 代理,能够解决各类复杂多变的任务。与传统 AI 助手不同,Manus 不仅能提供建议或答案,还能直接交…

压测结丹-分布式压测

1、 通过多机负载扩展支持海量压力 HttpRunner v4.2 起,hrp 可支持 master (负载控制器) 与 worker (压力生成器) 模式下启动,基于「一主多从」的负载加压模式实现海量并发。 功能特性 支持使用 auto-start / http-api 控制压测流程 支持任务自动下发(e.g. 参数化、自定义函…