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

20251201 - 换根dp总结

20251201 - 换根dp总结

换根 dp,就是先预处理出一些信息,然后再转移。

一般的可以先考虑子树内的答案,在扩展到字树外。

扩展到字树外可以先考虑根节点到他的子节点的转移,在扩展到其他的点。

例题

P1395 会议

这道题可以先求出以 1 号点为根的子树的大小,那么子树外的大小就是 n - siz[u]

预处理出来后,枚举每一个点,统计求 min 就好了。

#include <bits/stdc++.h>using namespace std;
#define ll long long
const int N = 1e5 + 7;
const int P = 998244353;
const int inf = (1 << 30);
template<class T> void read(T &x){x = 0;int f = 1;char ch = getchar();while(!(ch >= '0' && ch <= '9')){if(ch == '-') f = -f;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}x *= f;
}
int n;
vector<int> edges[N];
int pre[N], siz[N], dist[N];
inline void solve(int u, int from) {siz[u] = 1;for (auto v : edges[u]) {if (v == from) continue;pre[v] = u;solve(v, u);siz[u] += siz[v];}
}
inline void dfs(int u, int from) {for (auto v : edges[u]) {if (v == from) continue;dist[v] = dist[u] + 1;dfs(v ,u);}
}
int main(){read(n);for (int i = 1; i < n; i++) {int x, y;read(x), read(y);edges[x].push_back(y);edges[y].push_back(x);}pre[1] = -1;solve(1, 1);int id = 0, ans = inf;for (int i = 1; i <= n; i++) {int now_ans = 0;for (auto v : edges[i]) {if (pre[v] == i) {now_ans = max(now_ans, siz[v]);}else {now_ans = max(now_ans, n - siz[i]);}}if (now_ans < ans) {ans = now_ans;id = i;}}dfs(id, id);printf("%d %d\n", id, accumulate(dist + 1, dist + n + 1, 0));return 0;
}

P3478 STA-Station

题目可以转换成选择一个点,从这个点出发,到达每一个点的路径和最大。

那么可以设 siz[i] 为以 i 为根的子树的节点数,f[i] 为从 i 到子树内的点的和。

那么 f[u] 可以由 f[v] + siz[v] 来转移(因为从 u -> v,多了 siz[v] 个点)。

再设 c[i] 为从 i 到子树外的点的和。

u = 1 时,c[1] = 0,如果从 1 转移到 2,就会产生 (f[1] + c[1]) + (n - siz[2]) - (siz[2] + f[2]) 的贡献(总数 + 子树外 + 子树内)。

推广一下,就得 c[v] = (c[u] + f[u]) + (n - siz[v]) - (f[v] + siz[v])

最终的答案就是 \(\max _{1 \le i \le n} f[i] + c[i]\)

#include <bits/stdc++.h>using namespace std;
#define ll long long
const int N = 1e6 + 7;
const int P = 998244353;
const int inf = (1 << 30);
template<class T> void read(T &x){x = 0;int f = 1;char ch = getchar();while(!(ch >= '0' && ch <= '9')){if(ch == '-') f = -f;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}x *= f;
}
int n;
vector<int> edges[N];
ll siz[N], f[N], c[N];
inline void solve(int u, int from) {siz[u] = 1;for (auto v : edges[u]) {if (v == from) continue;solve(v, u);siz[u] += siz[v];f[u] += f[v] + siz[v];}
}
inline void dfs(int u, int from) {for (auto v : edges[u]) {if (v == from) continue;c[v] = (c[u] + f[u]) + (n - siz[v]) - (f[v] + siz[v]);dfs(v ,u);}
}
int main(){read(n);for (int i = 1; i < n; i++) {int x, y;read(x), read(y);edges[x].push_back(y);edges[y].push_back(x);}solve(1, 1);dfs(1, 1);// for (int i = 1; i <= n; i++) // printf("%d\n", c[i] + f[i]);ll id = 0, ans = 0;for (int i = 1; i <= n; i++) {if (c[i] + f[i] > ans)ans = c[i] + f[i], id = i;}printf("%lld\n", id);return 0;
}

树的直径

首先先从 \(1\) 号点进行 dfs,求出最大值,再从最大值做一遍 dfs,再次求最大值就好了。

证明见 树的直径 - OI Wiki。

http://www.jsqmd.com/news/57455/

相关文章:

  • 临时记录3
  • 临时记录2
  • RAG系统的随机失败问题排查:LLM的非确定性与表格处理的工程实践
  • 打包成.tar.gz文件命令
  • 北京最好的助贷机构推荐
  • 2025 上海徐汇区办公室装修公司推荐:本地化场景适配与优质服务商全景指南
  • Rust:借用 切片 - 指南
  • 门店违规防控与隐私保护系统:员工 NPS 升 47%,罚款零产生
  • 好文与笔记分享 A Survey of Context Engineering for Large Language Models(上) - 指南
  • 2025年12月份北京陪诊排行 优先推荐北京守嘉陪诊
  • DeepSeek-V3.2 Speciale介绍
  • Day52(22)-F:\硕士阶段\Java\课程代码\后端\web-ai-code\web-ai-project02
  • Redis 数据类型分布式锁
  • ESP32-LVGL 开发笔记(三):性能监控
  • 2025 阿联酋经济部商标注册平台 TOP4 实测:流程、费用与使用指南全解析
  • 2025 墨西哥商标注册渠道怎么选?3 大主流渠道测评 + 避坑指南
  • 2025年8款免费AI论文写作神器推荐!毕业论文轻松搞定
  • Typora的基础使用 - Edward
  • DP题单-衔接版
  • TCP/IP是什么?OSI又是什么? - 实践
  • 实用指南:(ACP广源盛)GSV6155---带嵌入式微控制器(MCU)和电源传输(PD)控制器的 Type-C/DisplayPort 1.4 信号中继器
  • 敏捷冲刺随笔-5
  • 美国商标注册代理公司哪家强?2025 实测榜单,注册成功率一目了然
  • 2025 国际商标注册平台测评:8 大头部机构实力排行 + 适配指南
  • 2025 印尼商标注册服务商哪家好?3大平台测评,帮你避开 90% 的坑
  • 从赋能到共创:技术负责人的团队赋能五层次模型
  • 【数位之和】除法和取余的使用
  • 基于空间变化单层神经网络先验的贝里标量-图像回归
  • 20251130-学习第一天
  • zy_蓝桥杯_C++学习系列一_语法基础