P2491 [SDOI2011]消防
这道题有点东西
首先,这道题如果有了这么个结论就没二分答案什么事情了:
这条长度不超过\(s\)的路径一定在直径上
所以就是和“树网的核”一个思路:在直径上面跑two-pointers,因为长度越长显然答案更优。
我们先求个直径,用两次dfs来求。
之后在直径上尺取的时候,当得到一段区间的时候,把直径两个端点到当前区间两个端点的距离计入答案。这里考虑直径内部对答案的贡献。
接下来考虑直径之外对答案的贡献。我们直接从直径上所有的点上面dfs,从所有不在直径上的点到直径的距离计入答案。
然后就完事了。我不会二分答案怎么做
代码:
/*************************************************************************
@Author: Garen
@Created Time : Tue 19 Feb 2019 08:05:33 AM CST
@File Name: P2491.cpp
@Description:
************************************************************************/
#include<bits/stdc++.h>
#define ll long long
const int maxn = 300005;
std::vector<std::pair<int,int> > G[maxn];
int fa[maxn], dep[maxn], weight[maxn];
int a[maxn], b[maxn], tot;
bool vis[maxn];
int n, s;
void bfs(int start, int &maxdep, int &idx) {
memset(dep, -1, sizeof dep);
memset(fa, 0, sizeof fa);
std::queue<int> q;
dep[start] = 0; q.push(start);
while(!q.empty()) {
int u = q.front(); q.pop();
if(dep[u] > maxdep) {
maxdep = dep[u]; idx = u;
}
for(auto it: G[u]) {
int v = it.first, w = it.second;
if(dep[v] == -1) {
dep[v] = dep[u] + w; fa[v] = u;
weight[v] = w;
q.push(v);
}
}
}
}
void get_diameter() {
int maxdep = -1, idx = -1;
bfs(1, maxdep, idx);
int temp = idx;
maxdep = -1, idx = -1;
bfs(temp, maxdep, idx);
while(idx != temp) {
a[++tot] = idx;
b[tot] = weight[idx];
idx = fa[idx];
}
a[++tot] = idx;
}
void dfs(int u, int f) {
fa[u] = f;
for(auto it: G[u]) {
int v = it.first, w = it.second;
if(vis[v] || v == f) continue;
dep[v] = dep[u] + w;
dfs(v, u);
}
}
int main() {
scanf("%d %d", &n, &s);
for(int i = 1; i < n; i++) {
int u, v, w; scanf("%d %d %d", &u, &v, &w);
G[u].push_back(std::make_pair(v, w));
G[v].push_back(std::make_pair(u, w));
}
get_diameter();
//for(int i = 1; i <= tot; i++) printf("%d ", a[i]);
int ans = 0x3f3f3f3f;
for(int l = 1, r = 0, sum = 0; l <= tot; l++) {
vis[a[l]] = true;
while(sum + b[r] <= s && r + 1 <= tot) {
sum += b[r]; r++;
}
//printf("%d %d\n", l, r);
ans = std::min(ans, std::max(dep[a[r]], dep[a[1]] - dep[a[l]]));
sum -= b[l];
}
for(int i = 1; i <= tot; i++) {
dep[a[i]] = 0; dfs(a[i], 0);
}
for(int i = 1; i <= n; i++) if(!vis[i]) ans = std::max(ans, dep[i]);
printf("%d\n", ans);
return 0;
}