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

简单树上问题

一、树的直径

1.两次DFS求树的直径

B4016 树的直径 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

先随便找一个点a,DFS一次找到最远距离的点u,再以u为起点DFS一次找到最远距离的点v,u到v即为树的直径

#include<bits/stdc++.h>
using namespace std;const int N = 1e5 + 10;
vector<int> g[N];
int d[N];void dfs(int now, int fa, int dep){d[now] = dep;for(auto &nex : g[now]){if(nex == fa) continue;dfs(nex, now, dep + 1);}
}int main() {int n; cin >> n;for(int i = 1; i <= n - 1; i++){int u, v; cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs(1, -1, 0);int s = 1;for(int i = 1; i <= n; i++){if(d[i] > d[s]) s = i;}dfs(s, -1, 0);int t = 1;for(int i = 1; i <= n; i++){if(d[i] > d[t]) t = i;}cout << d[t];
}

2.树形DP求树的直径

可以用于处理负权边

vector<int> g[N];
int dp[N], len;
void dfs(int now, int fa){for(auto &nex : g[now]){if(nex == fa) continue;dfs(nex, now);len = max(len, dp[now] + dp[nex] + 1);dp[now] = max(dp[now], dp[nex] + 1);		}
}

二、应用

1.距离问题

除直径两个端点以外,树中剩下的点所在的最长弦为该点到端点u的弦或者端点v的弦

Problem - 1805D - Codeforces

#include<bits/stdc++.h>
using namespace std;const int N = 2e5 + 10;
vector<int> g[N];
int d[N], dd[N], ans[N];void dfs(int now, int fa, int dep){d[now] = dep;for(auto &nex : g[now]){if(nex == fa) continue;dfs(nex, now, dep + 1);}
}
void dfs2(int now, int fa, int dep){dd[now] = dep;for(auto &nex : g[now]){if(nex == fa) continue;dfs2(nex, now, dep + 1);}
}int main() {int n; cin >> n;for(int i = 1; i <= n - 1; i++){int u, v; cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs(1, -1, 0);int s = 1;for(int i = 1; i <= n; i++){if(d[i] > d[s]) s = i;}dfs(s, -1, 0);int t = 1;for(int i = 1; i <= n; i++){if(d[i] > d[t]) t = i;}dfs2(t, -1, 0);for(int i = 1 ; i <= n ; i++)	if(i != t)	ans[max(d[i] , dd[i]) + 1]++ ;ans[0] = 1 ;for(int i = 1 ; i <= n ; i++)	ans[i] += ans[i - 1] , cout << ans[i] << ' ' ;
//	for(int i = 1; i <= n; i++){
//		cout << d[i] << ' ' << dd[i] << '\n';
//	}
}

2.记录直径上的点

用一个pre数组来记录每个点的先导点

Problem - 1294F - Codeforces

#include<bits/stdc++.h>
using namespace std;const int N = 2e5 + 10;
vector<int> g[N];
int d[N], pre[N];
bitset<N> vis;
int k, s, t;void dfs(int now, int fa, int dep){d[now] = dep;if(vis[now]) d[now] = 0, dep = 0;if(d[now] > d[k] && now != s && now != t){k = now;}pre[now] = fa;for(auto &nex : g[now]){if(nex == fa) continue;dfs(nex, now, dep + 1);}
}int main() {int n; cin >> n;for(int i = 1; i <= n - 1; i++){int u, v; cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs(1, -1, 0);s = k;k = 0;dfs(s, -1, 0);t = k;k = 0;int temp = t;vector<int> path;path.push_back(t);while(pre[temp] != -1){path.push_back(pre[temp]);temp = pre[temp];}for(auto &i : path) vis[i] = true;int ans = d[t];
//	for(int i = 1; i <= n; i++) d[i] = 0;dfs(s, -1, 0);ans += d[k];
//	for(int i = 1; i <= n; i++) cout << d[i] << ' ';
//	cout << '\n';cout << ans << '\n';if(k == 0){for(int i = 1; i <= n; i++){if(i != s && i != t){k = i;break;}}}cout << s << ' ' << t << ' ' << k;
}

3.和并查集一起拷打

并查集判断是否连通,合并计算新直径时一种结果为取原来图中的大直径,另一种为连接两个图直径的中点

Problem - 455C - Codeforces

#include<bits/stdc++.h>
using namespace std;
#define qio ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
typedef long long ll;const int N = 3e5 + 10;
int pre[N];
int root(int x){return pre[x] = (pre[x] == x ? x : root(pre[x]));
}
void merge(int u, int v){pre[root(u)] = root(v);
}
bool isCon(int u, int v){return root(u) == root(v);
}vector<int> g[N];
int dp[N], len;
void dfs(int now, int fa){for(auto &nex : g[now]){if(nex == fa) continue;dfs(nex, now);len = max(len, dp[now] + dp[nex] + 1);dp[now] = max(dp[now], dp[nex] + 1);		}
}
bitset<N> vis;
ll c[N];
ll caldep(int x){len = 0;dfs(x, -1);return len;
}int main() {int n, m, q; cin >> n >> m >> q;for(int i = 1; i <= n; i++) pre[i] = i;for(int i = 1; i <= m; i++){int u, v; cin >> u >> v;merge(u, v);g[u].push_back(v);g[v].push_back(u);}for(int i = 1; i <= n; i++){if(pre[i] != i || vis[i]) continue;c[i] = caldep(i);vis[i] = true;}
//	for(int i = 1; i <= n; i++) cout << c[i] << '\n';while(q--){int op; cin >> op;if(op == 2){int u, v; cin >> u >> v;if(isCon(u, v)) continue;ll t = (c[root(u)] + 1) / 2 + (c[root(v)] + 1) / 2 + 1;t = max(t, max(c[root(u)], c[root(v)]));merge(u, v);c[root(u)] = t;}else{int x; cin >> x;cout << c[root(x)] << '\n';}}}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Java核心API——exception类认识java异常处理机制
  • 网页html版——在线查字典的一个web服务器
  • “智能化自动化” 架构之3:中间建模脑的领域驱动设计的“同声传译”技能
  • TeamTalk路由服务器
  • 深度学习100问44:如何避免模型出现过拟合现象
  • 解决Selenium已安装,在pycharm导入时报错
  • K8s系列之:K8s OPERATOR是什么
  • Python matplotlib绘图 plt.barh 水平条形图调整顺序逆序排列
  • Docker 的安全优化
  • Git版本控制策略:Rebase还是Merge?详解优缺点与适用场景
  • 【 OpenHarmony 系统应用源码魔改 】-- Launcher 之「桌面布局定制」
  • 012 MPLS技术在企业网络中的应用
  • 深度学习100问42:什么是GNMT
  • 每天五分钟计算机视觉:人脸识别网络FaceNet
  • adb大全指令(持续更新)
  • JavaScript类型识别
  • JAVA多线程机制解析-volatilesynchronized
  • MobX
  • 不上全站https的网站你们就等着被恶心死吧
  • 关于List、List?、ListObject的区别
  • 入手阿里云新服务器的部署NODE
  • 微信小程序开发问题汇总
  • 项目管理碎碎念系列之一:干系人管理
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • # Redis 入门到精通(七)-- redis 删除策略
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #FPGA(基础知识)
  • #每天一道面试题# 什么是MySQL的回表查询
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (20)docke容器
  • (C语言)球球大作战
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (附源码)计算机毕业设计高校学生选课系统
  • (转) Face-Resources
  • *** 2003
  • **《Linux/Unix系统编程手册》读书笔记24章**
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .NET 项目中发送电子邮件异步处理和错误机制的解决方案
  • .net快速开发框架源码分享
  • @property python知乎_Python3基础之:property
  • @Validated和@Valid校验参数区别
  • [24年新算法]NRBO-XGBoost回归+交叉验证基于牛顿拉夫逊优化算法-XGBoost多变量回归预测
  • [ACM] hdu 1201 18岁生日
  • [AHK] WinHttpRequest.5.1报错 0x80092004 找不到对象或属性
  • [AUTOSAR][诊断管理][ECU][$37] 请求退出传输。终止数据传输的(上传/下载)
  • [C#] 基于 yield 语句的迭代器逻辑懒执行
  • [C#]DataTable常用操作总结【转】
  • [C++进阶篇]STL中vector的使用
  • [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子
  • [CentOs7]搭建ftp服务器(2)——添加用户
  • [Codeforces1137D]Cooperative Game
  • [CP_AUTOSAR]_分层软件架构_接口之通信模块交互介绍
  • [Editor]Unity Editor类常用方法
  • [Gym-102091E] How Many Groups