Address
https://www.lydsy.com/JudgeOnline/problem.php?id=2599
Solution
看到
才
,考虑如何求经过一个点
的长度为
的路径的边数最小值。
以
为根,顺序遍历
的每个子树,计算每个点到
的距离,称为
。用一个数组
,保存对于每个
,所有遍历过的子树内的点(包括
)中满足
的点
的(
的深度
的深度)的最小值。遍历之前只有
被遍历过,因此
, 对于所有的
,
。
如果当前在遍历
(
的子节点)的子树。那么
里保存了
即
之前的子树(不包括
的子树)内的信息。而如果
的子树内有一个点
,
到
的距离为
,
到
经过的边数为
,那么可以设想,存在一条路径:
在
的
之前的子树内,
到
的距离为
,
到
的距离为
,此路径为
。
那么,就可以用:
更新答案。
遍历完 的子树后,还要对于子树内的每个点 ,
但题目求的不仅仅是经过 的路径,因此用点分治,每次对分治出的子树都进行上述操作。 复杂度 。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Edge(u) for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 2e5 + 5, M = N << 1, E = 1e6 + 5, INF = 0x3f3f3f3f;
int n, K, ecnt, nxt[M], adj[N], go[M], val[M], sze[N], maxs[N], dis[N], orz[E],
ans = INF, tot, sp[N], dep[N]; bool vis[N];
void add_edge(int u, int v, int w) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u; val[ecnt] = w;
}
void dfs1(int u, int fu) {
sze[u] = 1; maxs[u] = 0; Edge(u) if (v != fu && !vis[v]) dfs1(v, u),
sze[u] += sze[v], maxs[u] = max(maxs[u], sze[v]);
}
void dfs2(int u, int fu, int r, int &G) {
maxs[u] = max(maxs[u], sze[r] - sze[u]);
Edge(u) if (v != fu && !vis[v]) dfs2(v, u, r, G); if (maxs[u] < maxs[G]) G = u;
}
int calcG(int u) {int G = u; dfs1(u, 0); dfs2(u, 0, u, G); return G;}
void dfs(int u, int fu, int d) {
if (dis[u] > K) return; sp[++tot] = dis[u]; dep[tot] = d;
Edge(u) if (v != fu && !vis[v]) dis[v] = dis[u] + val[e], dfs(v, u, d + 1);
}
void xyz32768issoweak(int u) {
int i, G = calcG(u); vis[G] = 1; orz[0] = tot = 0; Edge(G) if (!vis[v]) {
int tmp = tot; dis[v] = val[e]; dfs(v, G, 1);
For (i, tmp + 1, tot) ans = min(ans, dep[i] + orz[K - sp[i]]);
For (i, tmp + 1, tot) orz[sp[i]] = min(orz[sp[i]], dep[i]);
}
orz[0] = INF; For (i, 1, tot) orz[sp[i]] = INF;
Edge(G) if (!vis[v]) xyz32768issoweak(v);
}
int main() {
memset(orz, INF, sizeof(orz));
int i, x, y, z; n = read(); K = read(); For (i, 1, n - 1)
x = read() + 1, y = read() + 1, z = read(), add_edge(x, y, z);
if (K == 0) return puts("0"), 0; xyz32768issoweak(1);
if (ans == INF) return puts("-1"), 0; cout << ans << endl; return 0;
}