[题解] [SDOI2011] 消防
[题解] [SDOI2011] 消防
tag: 图论
、树
、树的直径
题目链接(洛谷):https://www.luogu.com.cn/problem/P2491
题目描述#
给定一棵
数据范围:
题解#
不难得出结论:如果没有
那么新的问题是,对于一条确定的直径上的路径,如何求得距离该路径最远的点的距离。我们按照将直径缩短的思路思考。最初始的情况,我们要考虑不在直径上的点到直径的距离,可以利用 DFS ,从每个直径上的点向不在直径上的点遍历,在
AC 代码#
//
// Created by wxy3265 on 2024/10/3.
//
#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
using namespace std;
const int MAXN = 2e7 + 5e6;
const int MAXM = 2e7 + 5e6;
// 建图
int first[MAXN], v[MAXM], nt[MAXM], w[MAXM];
int te;
inline void addEdge(int x, int y, int ww) {
nt[++te] = first[x];
first[x] = te;
v[te] = y;
w[te] = ww;
}
// 第一次 DFS 找到直径的一端
int maxd, maxdi;
void dfs1(int x, int fa, int step) {
if (step > maxd) maxd = step, maxdi = x;
for (int eo = first[x]; eo; eo = nt[eo]) {
const int ep = v[eo];
if (ep == fa) continue;
dfs1(ep, x, step + w[eo]);
}
}
// 第二次 DFS 找到直径,同时求出直径上相邻点及距离(nxt、nw)
int f[MAXN], nxt[MAXN], nw[MAXN];
void dfs2(int x, int fa, int step) {
for (int eo = first[x]; eo; eo = nt[eo]) {
const int ep = v[eo];
if (ep == fa) continue;
dfs2(ep, x, step + w[eo]);
if (f[ep] > f[x]) {
f[x] = f[ep];
nxt[x] = ep;
nw[x] = w[eo];
}
}
if (!f[x]) f[x] = step;
}
// 第三次 DFS 求出从各直径上的点出发不经过其他直径上的点的最远距离
bool id[MAXN];
int mx[MAXN];
void dfs3(int x, int fa) {
for (int eo = first[x]; eo; eo = nt[eo]) {
const int ep = v[eo];
if (ep == fa || id[ep]) continue;
dfs3(ep, x);
mx[x] = max(mx[x], mx[ep] + w[eo]);
}
}
int q[MAXN], head = 0, tail = 0;
signed main() {
// 读入数据
int n, s;
cin >> n >> s;
for (int i = 1; i <= n - 1; i++) {
int x, y, ww;
cin >> x >> y >> ww;
addEdge(x, y, ww);
addEdge(y, x, ww);
}
// 求直径
dfs1(1, 0, 0);
dfs2(maxdi, 0, 0);
int tot = 0;
head = 1;
for (int i = maxdi; i != 0; i = nxt[i]) {
q[++tail] = i;
tot += nw[i];
id[i] = true;
}
// 求初始答案
int r = tail, now = tot, ans = 0, tmp = tot;
for (int i = 1; i <= n; i++) {
if (id[i]) {
dfs3(i, 0);
ans = max(ans, mx[i]);
}
}
// 双指针遍历
int dr = 0, dl = 0;
while (head <= s) {
while (r >= head && now > s) {
r--;
now -= nw[q[r]];
dr += nw[q[r]];
}
tmp = min(tmp, max(dr, dl));
dl += nw[q[head]];
now -= nw[q[head]];
head++;
while (r <= tail && now + nw[q[r]] <= s) {
now += nw[q[r]];
dr -= nw[q[r]];
r++;
}
}
cout << max(ans, tmp) << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效