赛前训练 12 树的直径、中心和重心

news/2025/10/19 21:46:44/文章来源:https://www.cnblogs.com/XOF-0-0/p/19151489

A

树的直径板子.

B

注意到树的直径有个性质:所有节点到其他点的最远距离一定在直径的端点处取到.怎么证明请查阅往期笔记.

这样,我们把直径留着,将其他点依次和端点匹配,最后加上直径的贡献就得到了第一问的答案.

那么如何输出方案?画个图可以发现取出其他点的过程类似于拓扑排序,于是我们模拟一遍拓扑排序即可.最后直径跳 fa 输出就好啦.

实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;const int N=2e5+5;
int n,x,y;
int dis[N],dis2[N],dg[N],f[N];
bool vis[N];
struct NODE{int v,w;
};
vector<NODE> G[N];void dfs(int cur,int fa,int *d){f[cur]=fa;for(auto [i,w]:G[cur]){if(i==fa)continue;d[i]=d[cur]+1;dfs(i,cur,d);}
}
void mark(){int cur=x;while(cur!=y){vis[cur]=1;cur=f[cur];}vis[y]=1;
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n;for(int i=1,u,v;i<n;i++){cin>>u>>v;G[u].push_back({v,0});G[v].push_back({u,0});dg[u]++,dg[v]++;}dfs(1,0,dis);for(int i=1;i<=n;i++)if(dis[x]<dis[i])x=i;memset(dis,0,sizeof dis);dfs(x,0,dis);for(int i=1;i<=n;i++)if(dis[y]<dis[i])y=i;dfs(y,0,dis2);int ans=dis[y]*(dis[y]+1)/2;mark();for(int i=1;i<=n;i++)if(!vis[i])ans+=max(dis[i],dis2[i]);cout<<ans<<'\n';queue<int> q;for(int i=1;i<=n;i++)if(dg[i]==1&&!vis[i])q.push(i);while(!q.empty()){int cur=q.front(),cur2=y;if(dis[cur]>dis2[cur])cur2=x;cout<<cur<<' '<<cur2<<' '<<cur<<'\n';q.pop();for(auto [i,w]:G[cur]){if(vis[i])continue;dg[i]--;if(dg[i]==1)q.push(i);}}int cur=x;while(cur!=y){cout<<cur<<' '<<y<<' '<<cur<<'\n';cur=f[cur];}return 0;
}

C

一个强力性质:两棵树连在一起后要求直径最大必须连中心,因为最长链都经过中心.于是这个题枚举断开的边然后暴力求中心连边最后求直径取 \(\max\) 即可.怎么都是性质题呜呜呜被薄纱了

实现
#include<bits/stdc++.h>
#define int long long
using namespace std;const int N=5e3+5;
int n,ans=1e18,f[N];
int dis,dis1,dis2;
struct E{ int v,w; };
vector<E> T[N<<1];
int len1[N],len2[N],up[N];
bool vis[N];
int u[N],v[N],w[N];inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;
}
void dfsd(int cur,int fa){vis[cur]=1;for(auto i:T[cur]){if(i.v==fa) continue;dfsd(i.v,cur);if(len1[i.v]+i.w>len1[cur])len2[cur]=len1[cur],len1[cur]=len1[i.v]+i.w;else if(len1[i.v]+i.w>len2[cur])len2[cur]=len1[i.v]+i.w;}dis=max(dis,len1[cur]+len2[cur]);
}
void dfsu(int cur,int fa){for(auto i:T[cur]){if(i.v==fa) continue;up[i.v]=up[cur]+i.w;if(len1[i.v]+i.w!=len1[cur])up[i.v]=max(up[i.v],len1[cur]+i.w);elseup[i.v]=max(up[i.v],len2[cur]+i.w);dfsu(i.v,cur);}
}
int fnd(int x){return (f[x]==x?x:f[x]=fnd(f[x]));
}
void uni(int x,int y){x=fnd(x),y=fnd(y);if(x!=y) f[x]=y;
}signed main(){//ios::sync_with_stdio(0);n=read();for(int i=1;i<n;i++)u[i]=read(),v[i]=read(),w[i]=read();for(int i=1;i<n;i++){for(int j=1;j<=n;j++) f[j]=j;for(int j=1;j<=n;j++) T[j].clear();for(int j=1;j<=n;j++) len1[j]=len2[j]=up[j]=0; dis1=dis2=0;for(int j=1;j<n;j++)if(j!=i) uni(u[j],v[j]),T[u[j]].push_back({v[j],w[j]}),T[v[j]].push_back({u[j],w[j]});dis=0,dfsd(u[i],0);dis1=dis;dis=0,dfsd(v[i],0);dis2=dis;dfsu(u[i],0),dfsu(v[i],0);int minx=1e18,miny=1e18;for(int j=1;j<=n;j++){if(fnd(j)==fnd(u[i])&&minx>max(len1[j],up[j]))minx=max(len1[j],up[j]);if(fnd(j)==fnd(v[i])&&miny>max(len1[j],up[j]))miny=max(len1[j],up[j]);}ans=min(ans,max({dis1,dis2,w[i]+minx+miny}));}cout<<ans;return 0;
}

D

因为 \(F\) 位于直径上且具有长度限制,所以很容易想到双指针维护 \(F\).

求出 \(F\) 之后,设其上端点为 \(i\),下端点为 \(j\),那么它的 \(\text{ECC}\) 存在三种情况:

  • 直径的下端点到 \(j\) 的长度

  • 直径上端点到 \(i\) 的长度

  • 直径外部的点连到 \(F\) 的长度.

前两个维护 \(F\) 的时候可以顺便求出,而第三个则可以对直径上每个点跑一遍 DFS 求出最长距离即可.三者取 \(\max\) 即为答案.时间复杂度 \(\mathcal{O}(n)\).

实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;const int N=1e3+5;
int n,s;
int dis[N],f[N];
bool vis[N];
struct NODE{int v,w;
};
vector<NODE> G[N];void dfs(int cur,int fa){f[cur]=fa;for(auto [i,w]:G[cur]){if(i==fa||vis[i])continue;dis[i]=dis[cur]+w;dfs(i,cur);}
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n>>s;for(int i=1,u,v,w;i<n;i++){cin>>u>>v>>w;G[u].push_back({v,w});G[v].push_back({u,w});}dfs(1,0);int p=0,ans=1e18;for(int i=1;i<=n;i++)if(dis[p]<dis[i])p=i;memset(dis,0,sizeof dis);dfs(p,0);for(int i=1;i<=n;i++)if(dis[p]<dis[i])p=i;for(int i=p,j=p;i;i=f[i]){vis[i]=1;for(;dis[j]-dis[i]>s;j=f[j]);ans=min(ans,max(dis[i],dis[p]-dis[j]));}for(int i=p;i;i=f[i])dis[i]=0,dfs(i,f[i]);for(int i=1;i<=n;i++)ans=max(ans,dis[i]);cout<<ans;return 0;
}

总结

这三个知识点对应的性质记得考前记背.

树上路径转序列先以一个端点进行 dfs.

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

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

相关文章

我要好好写博客了 - Milo

1 目的 记录自己在编程过程中遇到的问题和想法,以及在学习新知识时的知识点 2 为什么突然想要好好经营一个博客 我很喜欢互联网的开源精神,我是2020年上的大一,在大四的时候,AI出现了。 在AI出现之前,我的几乎所有…

关于无人巡航小车的学习笔记

文件名:zmd_ws zmd为队伍名称,下横杠代替空格,ws全称为workspace,即工作空间。工作空间的分隔原理暂时不知道? 文件名:build,devel 用于存放执行catkin_make后的编译文件,也就是编译ROS(src文件夹下)包时所…

[fastgrind] 一个轻量级C++内存监控及可视化开源库

目录Fastgrind引言 简介 仓库结构 快速开始编译 testcase 运行 testcase 调用堆栈 Report如何在你的项目中使用手动插桩的使用方法 自动插桩的使用方法fastgrind 输出与分析fastgrind.text fastgrind.json可视化 fastg…

详细介绍:springboot+vue智慧旅游管理小程序(源码+文档+调试+基础修改+答疑)

详细介绍:springboot+vue智慧旅游管理小程序(源码+文档+调试+基础修改+答疑)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-f…

iOS/Swift:深入理解iOS CoreText API

iOS/Swift:深入理解iOS CoreText API这篇文章是从0到1自定义富文本渲染的原理篇之一,此外你还可能感兴趣:一文读懂字符与编码 一文读懂字符、字形、字体 一文读懂字体文件 从0到1自定义文字排版引擎:原理篇 逆向分…

存算一体架构的先行者:RustFS在异构计算环境下的探索与实践

存算一体架构的先行者:RustFS在异构计算环境下的探索与实践随着AI大模型与边缘计算蓬勃发展,传统"存储-计算"分离架构的"存储墙"瓶颈日益凸显。本文将深入解析RustFS如何通过存算一体设计在异构…

Appium 3.0:跨平台移动自动化测试框架全面解析

Appium是一个开源的跨平台自动化测试框架,支持原生、混合、移动Web和桌面应用的测试。基于WebDriver协议,提供丰富的驱动和插件生态系统,支持多种编程语言,让移动应用测试变得更加简单高效。Appium 3.0:跨平台移动…

德国州政府全面弃用微软办公套件,改用开源方案

德国州政府全面弃用微软办公套件,改用开源方案德国州政府全面弃用微软办公套件,改用开源方案来源: OSCHINA 编辑: 局 2025-10-16 19:24:043德国石勒苏益格 - 荷尔斯泰因州宣布,已正式完成从微软 Outlook 和 Exchang…

DAPO代码实现浅析

参考verl对dapo的实现,首先咱们看一下入口.sh和.py文件,在./recipe/dapo/文件夹中有以下目录 . ├── config │ ├── dapo_megatron_trainer.yaml │ └── dapo_trainer.yaml ├── dapo_ray_trainer.py …

[KaibaMath]1011 关于收敛数列保号性的证明

[KaibaMath]1011 关于收敛数列保号性的证明收敛数列保号性是描述收敛数列的极限符号与数列“后期项”符号关系的核心性质,即极限的非零符号能“保证”数列从某一项开始的所有项与极限同号。下面给出证明。

赛前训练 12 extra 树上差分倍增

A 树上差分板子. B 每个点只有一条出边的有向图可以看作树 基于上述结论,我们直接倍增维护 \(\min,\operatorname{sum}\) 即可.实现 #include <cstdio> #include <iostream> #include <algorithm> #…

塔吊施工人员操作合规性监测!思通数科 AI 卫士实时守护作业安全

塔吊施工中,人员操作合规性是安全管理的关键环节,但传统人工监管常面临 “监管范围有限、异常难实时发现” 的痛点:作业人员是否按规范穿戴防护装备(安全帽、防护服、防护手套),靠远处观察难判断穿戴完整性(如安…

Dos命令1

常用的dos命令 我不懂

题解:P1073 [NOIP 2009 提高组] 最优贸易

题目传送门 绝世好题 让我学会了分层图的真正用法 以前都只会自作聪明地分两层: 美其名曰【正图】【反图】 现在知道了还有这种神奇的建图方法!理解题意: 有向图 给定起点终点 求路径上两点买卖东西最大收益 思路:…

吩咐

吩咐rt。不知道要写些什么。 Q/A 或者别的。 记忆力可能比较差,可能会有内容错乱。Q以下是博客签名,正文无关 本文来自博客园,作者:Wy_x,转载请在文首注明原文链接:https://www.cnblogs.com/Wy-x/p/19151449 版权…

互评五

一、数据存储结构不同 ArrayImpl: 使用固定大小的数组 Student[] students ListImpl: 使用动态数组 ArrayList students 构造函数差异 ArrayImpl: 需要指定初始大小 public StudentDaoArrayImpl(int size) ListImpl: 无…

ACS ACR122 0 是啥

ACS ACR122 0 是啥你提到的 “ACS ACR122 0”,实际上指的是一个 NFC 读卡器(RFID Reader)。 下面我详细给你讲清楚它是什么、怎么用、以及它为什么会在系统里显示成那个名字。🪪 一、设备全称 ACS ACR122U NFC Re…

C++ std::forwardT 的使用

C++ std::forwardC++ std::forward 的使用 C++真实一门细节比较多的语言,稍不注意就会出现奇怪请琢磨不透的bug,这时候就说明你的C++基础不扎实。 C++ lvalue rvalue std::string hello = "Hello World";顾…

机器人技术新前沿:自动驾驶路径规划算法解析

本文深入探讨了自动驾驶机器人出租车技术的核心算法,包括基于机器学习的路径规划、环境感知与行为预测系统,并对比了火星探测器与城市自动驾驶在技术挑战上的差异。机器人技术新前沿 某中心子公司Zoox首席软件工程师…

前端框架文档新思路:基于源码解析的自动化方案

项目背景 最近我们团队自研了一个基于 React 的 H5 前端框架,领导让我来负责编写框架的使用文档。我选择了 dumi 来搭建文档站点,大部分内容都是手动写 Markdown 来介绍各种功能,包括:初始化、目录结构、生命周期、…