제출 #1339460

#제출 시각아이디문제언어결과실행 시간메모리
1339460ladnoooo경주 (Race) (IOI11_race)C++20
100 / 100
286 ms45804 KiB
#include <vector>
#include <algorithm>

using namespace std;

#define pb push_back
#define int long long
#define INF 1e18

const int MAXN = 200005;
const int MAXK = 1000005;

struct Edge {
    int to, len;
};

vector<Edge> adj[MAXN];
int sz[MAXN], deleted[MAXN];
int min_edges[MAXK]; // min_edges[d] - мин. ребер для пути длиной d
vector<int> changed_indices; 
int ans = INF;
int current_k;

// Считаем размеры поддеревьев
void get_sz(int v, int p) {
    sz[v] = 1;
    for (auto& edge : adj[v]) {
        if (edge.to != p && !deleted[edge.to]) {
            get_sz(edge.to, v);
            sz[v] += sz[edge.to];
        }
    }
}

// Ищем центроид
int get_centroid(int v, int p, int n) {
    for (auto& edge : adj[v]) {
        if (edge.to != p && !deleted[edge.to] && sz[edge.to] > n / 2) {
            return get_centroid(edge.to, v, n);
        }
    }
    return v;
}

// Собираем пути из текущего поддерева
void get_paths(int v, int p, int depth, int dist, vector<pair<int, int>>& paths) {
    if (dist > current_k) return;
    paths.pb({dist, depth});
    for (auto& edge : adj[v]) {
        if (edge.to != p && !deleted[edge.to]) {
            get_paths(edge.to, v, depth + 1, dist + edge.len, paths);
        }
    }
}

void decompose(int v) {
    get_sz(v, -1);
    int centroid = get_centroid(v, -1, sz[v]);
    deleted[centroid] = 1;

    changed_indices.clear();
    min_edges[0] = 0;
    changed_indices.pb(0);

    for (auto& edge : adj[centroid]) {
        if (!deleted[edge.to]) {
            vector<pair<int, int>> paths;
            get_paths(edge.to, centroid, 1, edge.len, paths);

            // 1. Проверяем пути, проходящие через центроид
            for (auto& p : paths) {
                if (current_k >= p.first) {
                    ans = min(ans, p.second + min_edges[current_k - p.first]);
                }
            }

            // 2. Обновляем min_edges для следующих веток
            for (auto& p : paths) {
                if (p.first <= current_k) {
                    if (min_edges[p.first] == -1 || p.second < min_edges[p.first]) {
                        if (min_edges[p.first] == INF) changed_indices.pb(p.first);
                        min_edges[p.first] = p.second;
                    }
                }
            }
        }
    }

    // Очистка min_edges для следующего центроида (эффективнее, чем memset)
    for (int idx : changed_indices) min_edges[idx] = INF;

    for (auto& edge : adj[centroid]) {
        if (!deleted[edge.to]) {
            decompose(edge.to);
        }
    }
}

// Основная функция по условию [cite: 14]
signed best_path(signed N, signed K, signed H[][2], signed L[]) {
    current_k = K;
    ans = INF;
    for (int i = 0; i < N; i++) {
        adj[i].clear();
        deleted[i] = 0;
    }
    for (int i = 0; i <= K; i++) min_edges[i] = INF;

    for (int i = 0; i < N - 1; i++) {
        adj[H[i][0]].pb({H[i][1], L[i]});
        adj[H[i][1]].pb({H[i][0], L[i]});
    }

    decompose(0);

    if (ans >= INF) return -1; // Если путь не найден [cite: 21, 53]
    return (signed)ans;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...