제출 #1271158

#제출 시각아이디문제언어결과실행 시간메모리
1271158teste경주 (Race) (IOI11_race)C++20
100 / 100
815 ms52400 KiB
#include <iostream>
#include <vector>
#include <algorithm>
#include <map> // Usar map ao invés de unordered_map pode ser mais estável em alguns casos.
#include "race.h"

using namespace std;

const int INF = 1e9; // Um infinito maior é mais seguro

int N_global;
long long K_global;
vector<vector<pair<int, int>>> adj; // {vizinho, peso}
vector<int> subtree_size;
vector<bool> is_removed;
int min_edges = INF;

// Calcula o tamanho das subárvores
void get_subtree_sizes(int u, int p) {
    subtree_size[u] = 1;
    for (auto& edge : adj[u]) {
        int v = edge.first;
        if (v != p && !is_removed[v]) {
            get_subtree_sizes(v, u);
            subtree_size[u] += subtree_size[v];
        }
    }
}

// Encontra o centroide da árvore/subárvore atual
int get_centroid(int u, int p, int total_size) {
    for (auto& edge : adj[u]) {
        int v = edge.first;
        if (v != p && !is_removed[v] && subtree_size[v] * 2 > total_size) {
            return get_centroid(v, u, total_size);
        }
    }
    return u;
}

// DFS para encontrar todos os caminhos a partir do centroide
// Armazena os pares {comprimento, num_arestas}
void dfs_paths(int u, int p, long long current_len, int current_edges, vector<pair<long long, int>>& paths) {
    if (current_len > K_global) {
        return;
    }
    
    paths.push_back({current_len, current_edges});

    for (auto& edge : adj[u]) {
        int v = edge.first;
        int weight = edge.second;
        if (v != p && !is_removed[v]) {
            dfs_paths(v, u, current_len + weight, current_edges + 1, paths);
        }
    }
}


// Função principal da Decomposição por Centroide
void decompose(int entry_node) {
    get_subtree_sizes(entry_node, -1);
    int centroid = get_centroid(entry_node, -1, subtree_size[entry_node]);

    // Mapa para armazenar os melhores caminhos (comprimento -> min_arestas)
    // que começam no centroide atual.
    map<long long, int> best_paths;
    best_paths[0] = 0; // Caminho de comprimento 0 tem 0 arestas

    for (auto& edge : adj[centroid]) {
        int neighbor = edge.first;
        if (!is_removed[neighbor]) {
            vector<pair<long long, int>> paths_from_neighbor;
            // Coleta todos os caminhos na subárvore do vizinho
            dfs_paths(neighbor, centroid, edge.second, 1, paths_from_neighbor);

            // Para cada caminho encontrado, tenta achar um par no mapa 'best_paths'
            for (const auto& path : paths_from_neighbor) {
                long long len = path.first;
                int edges = path.second;
                if (K_global >= len) {
                    long long needed = K_global - len;
                    if (best_paths.count(needed)) {
                        min_edges = min(min_edges, edges + best_paths[needed]);
                    }
                }
            }

            // Adiciona os caminhos coletados ao mapa 'best_paths' para as próximas subárvores
            for (const auto& path : paths_from_neighbor) {
                long long len = path.first;
                int edges = path.second;
                if (!best_paths.count(len) || edges < best_paths[len]) {
                    best_paths[len] = edges;
                }
            }
        }
    }

    is_removed[centroid] = true;

    // Chama recursivamente para as subárvores restantes
    for (auto& edge : adj[centroid]) {
        int v = edge.first;
        if (!is_removed[v]) {
            decompose(v);
        }
    }
}


int best_path(int N, int K, int H[][2], int L[]) {
    // Reset de variáveis globais para múltiplos casos de teste (se houver)
    min_edges = INF;
    N_global = N;
    K_global = K;

    adj.assign(N, vector<pair<int, int>>());
    for (int i = 0; i < N - 1; i++) {
        int u = H[i][0];
        int v = H[i][1];
        int w = L[i];
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
    }

    subtree_size.assign(N, 0);
    is_removed.assign(N, false);
    
    decompose(0);

    return (min_edges == INF) ? -1 : min_edges;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...