This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
/*
Subproblem:
Given a tree with N nodes, find the minimum number of edges in a path whose total length is exactly K and
it either ends at the root or pass through the root.
root
/ | \
.. c_i c_(i + 1)
After processing the first i children of the root, let's say we know the following:
minEdges[length] -> Minimum number of edges in a path of length "length" such that it originates from the root
and ends up at the subtree of the first i children of the root.
When processing the (i + 1)-th children, we can utilize that value. For example, we are at a node whose distance from
the root is d, then the answer we seek to minize is: depth + minEdges[K - d].
This problem is solved in O(N log N) time.
To solve the full problem, we need to perform centroid decomposition. The total complexity will be O(N log^2(N))
*/
#include "race.h"
#include<bits/stdc++.h>
using namespace std;
#define INF 1000000000
#define MAXN 200000
int n, k, sz[MAXN + 3];
vector<pair<int, int> > adj[MAXN + 3];
bool isDecomposed[MAXN + 3];
unordered_map<int, int> minEdges;
int ans = INF;
void dfsSize(int u, int prev = -1) {
sz[u] = 1;
for (auto [v, cost]: adj[u]) {
if (v != prev && !isDecomposed[v]) {
dfsSize(v, u);
sz[u] += sz[v];
}
}
}
int doFindCentroid(int u, int subtreeSize, int prev = -1) {
for (auto [v, cost]: adj[u]) {
if (v != prev && !isDecomposed[v] && sz[v] * 2 > subtreeSize) {
return doFindCentroid(v, subtreeSize, u);
}
}
return u;
}
int findCentroid(int u) {
dfsSize(u);
return doFindCentroid(u, sz[u]);
}
void updateAnswer(int u, int prev, int currentDepth, int currentDist) {
if (minEdges.find(k - currentDist) != minEdges.end()) {
ans = min(ans, currentDepth + minEdges[k - currentDist]);
}
for (auto [v, cost]: adj[u]) {
if (v != prev) {
updateAnswer(v, u, currentDepth + 1, currentDist + cost);
}
}
}
void updateMinEdges(int u, int prev, int currentDepth, int currentDist) {
if (minEdges.find(currentDist) == minEdges.end()) {
minEdges[currentDist] = currentDepth;
} else {
minEdges[currentDist] = min(minEdges[currentDist], currentDepth);
}
for (auto [v, cost]: adj[u]) {
if (v != prev) {
updateMinEdges(v, u, currentDepth + 1, currentDist + cost);
}
}
}
void centroidDecomposition(int u) {
int centroid = findCentroid(u);
isDecomposed[centroid] = true;
for (auto [v, cost]: adj[centroid]) {
if (!isDecomposed[v]) {
updateAnswer(v, centroid, 1, cost);
updateMinEdges(v, centroid, 1, cost);
}
}
// Handle paths that end at the centroid
if (minEdges.find(k) != minEdges.end()) {
ans = min(ans, minEdges[k]);
}
minEdges.clear();
for (auto [v, cost]: adj[centroid]) {
if (!isDecomposed[v]) {
centroidDecomposition(v);
}
}
}
int best_path(int N, int K, int H[][2], int L[]) {
n = N;
k = K;
for (int i = 0; i < n - 1; i++) {
adj[H[i][0]].push_back({H[i][1], L[i]});
adj[H[i][1]].push_back({H[i][0], L[i]});
}
memset(isDecomposed, false, sizeof(isDecomposed));
centroidDecomposition(1);
if (ans < INF) {
return ans;
} else {
return -1;
}
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |