Submission #1188239

#TimeUsernameProblemLanguageResultExecution timeMemory
1188239ainunnajibToll (APIO13_toll)C++20
16 / 100
1 ms2632 KiB
#include <iostream> #include <vector> #include <numeric> #include <algorithm> #include <map> #include <vector> // Add missing include // --- Disjoint Set Union (DSU) --- struct DSU { std::vector<int> parent; DSU(int n) { parent.resize(n + 1); std::iota(parent.begin(), parent.end(), 0); } int find(int x) { if (parent[x] == x) return x; return parent[x] = find(parent[x]); } bool unite(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { parent[rootX] = rootY; return true; } return false; } }; // --- Edge Structures --- struct Edge { int u, v, cost, original_id; // original_id is 0 to M-1 }; struct NewEdgeInput { int id; // 0 to K-1 int u, v; }; // --- MST T0 & LCA / Path Max --- const int MAXN = 100005; const int LOGN = 18; // Max ~log2(MAXN) // Structure to store MST edges with neighbor, cost, and original_id struct MSTAdjInfo { int neighbor; int cost; int original_id; }; std::vector<MSTAdjInfo> adj_mst[MAXN]; // Adjacency list for MST T0 // For Binary Lifting LCA/Path Max int up[MAXN][LOGN]; int max_edge_cost[MAXN][LOGN]; // Stores max cost on path int max_edge_id[MAXN][LOGN]; // Stores original_id of the max cost edge int depth[MAXN]; std::map<int, long long> edge_flow; // Map original_id to its flow in T0 std::vector<long long> p_counts; // Participant counts (0-indexed) // DFS for LCA, Path Max precomputation, and storing parent edge info void dfs_lca_build(int u, int p_node, int p_cost, int p_edge_id, int d) { depth[u] = d; up[u][0] = p_node; max_edge_cost[u][0] = p_cost; max_edge_id[u][0] = p_edge_id; for (int i = 1; i < LOGN; ++i) { int ancestor = up[u][i - 1]; if (ancestor != 0) { // Check if ancestor exists up[u][i] = up[ancestor][i - 1]; if (max_edge_cost[u][i - 1] >= max_edge_cost[ancestor][i - 1]) { max_edge_cost[u][i] = max_edge_cost[u][i - 1]; max_edge_id[u][i] = max_edge_id[u][i - 1]; } else { max_edge_cost[u][i] = max_edge_cost[ancestor][i - 1]; max_edge_id[u][i] = max_edge_id[ancestor][i - 1]; } } else { // Handle case where 2^i ancestor doesn't exist up[u][i] = 0; max_edge_cost[u][i] = max_edge_cost[u][i-1]; // Inherit from previous level max_edge_id[u][i] = max_edge_id[u][i-1]; } } for (const auto& edge_info : adj_mst[u]) { int v = edge_info.neighbor; if (v != p_node) { dfs_lca_build(v, u, edge_info.cost, edge_info.original_id, d + 1); } } } // DFS to calculate subtree participant sums and edge flows long long dfs_flow_calc(int u, int p_node) { long long current_subtree_p = p_counts[u - 1]; // p_counts is 0-indexed for (const auto& edge_info : adj_mst[u]) { int v = edge_info.neighbor; if (v != p_node) { long long child_flow = dfs_flow_calc(v, u); edge_flow[edge_info.original_id] = child_flow; // Store flow by original_id current_subtree_p += child_flow; } } return current_subtree_p; } // Query Max Edge Info on Path u-v std::pair<int, int> query_path_max(int u, int v) { int max_c = 0; int max_id = -1; if (depth[u] < depth[v]) std::swap(u, v); for (int i = LOGN - 1; i >= 0; --i) { if (up[u][i] != 0 && depth[u] - (1 << i) >= depth[v]) { if (max_edge_cost[u][i] > max_c) { max_c = max_edge_cost[u][i]; max_id = max_edge_id[u][i]; } else if (max_edge_cost[u][i] == max_c) { // Tie-breaking? Assume distinct costs for now, or handle if needed. } u = up[u][i]; } } if (u == v) return {max_c, max_id}; for (int i = LOGN - 1; i >= 0; --i) { if (up[u][i] != up[v][i]) { // Compare and update max_c, max_id for both u and v paths if (max_edge_cost[u][i] > max_c) { max_c = max_edge_cost[u][i]; max_id = max_edge_id[u][i]; } if (max_edge_cost[v][i] > max_c) { max_c = max_edge_cost[v][i]; max_id = max_edge_id[v][i]; } u = up[u][i]; v = up[v][i]; } } // Compare last edges to LCA if (max_edge_cost[u][0] > max_c) { max_c = max_edge_cost[u][0]; max_id = max_edge_id[u][0]; } if (max_edge_cost[v][0] > max_c) { max_c = max_edge_cost[v][0]; max_id = max_edge_id[v][0]; } return {max_c, max_id}; // {max_cost, original_id_of_max_cost_edge} } // --- MWIS Solver (Backtracking) --- std::vector<std::vector<int>> conflict_adj; // Conflict graph adjacency list std::vector<long long> node_weights; // Revenue R_i for node i (0 to K-1) long long max_revenue_found = 0; std::vector<bool> is_selected; // Current selection in backtracking void solve_mwis(int k_idx, long long current_revenue) { if (k_idx == node_weights.size()) { max_revenue_found = std::max(max_revenue_found, current_revenue); return; } // Option 1: Don't include node k_idx solve_mwis(k_idx + 1, current_revenue); // Option 2: Try to include node k_idx bool conflict_exists = false; for (int neighbor : conflict_adj[k_idx]) { if (neighbor < k_idx && is_selected[neighbor]) { conflict_exists = true; break; } } if (!conflict_exists) { is_selected[k_idx] = true; solve_mwis(k_idx + 1, current_revenue + node_weights[k_idx]); is_selected[k_idx] = false; // Backtrack } } // --- Main --- int main() { std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int n, m, k_val; std::cin >> n >> m >> k_val; std::vector<Edge> original_edges_input(m); for (int i = 0; i < m; ++i) { std::cin >> original_edges_input[i].u >> original_edges_input[i].v >> original_edges_input[i].cost; original_edges_input[i].original_id = i; } std::vector<NewEdgeInput> new_edges_input(k_val); for (int i = 0; i < k_val; ++i) { new_edges_input[i].id = i; std::cin >> new_edges_input[i].u >> new_edges_input[i].v; } p_counts.resize(n); for (int i = 0; i < n; ++i) { std::cin >> p_counts[i]; } // 1. Compute MST T0 std::sort(original_edges_input.begin(), original_edges_input.end(), [](const Edge& a, const Edge& b) { return a.cost < b.cost; }); DSU dsu_mst(n); int mst_edge_count = 0; for (const auto& edge : original_edges_input) { if (dsu_mst.unite(edge.u, edge.v)) { adj_mst[edge.u].push_back({edge.v, edge.cost, edge.original_id}); adj_mst[edge.v].push_back({edge.u, edge.cost, edge.original_id}); mst_edge_count++; if (mst_edge_count == n - 1) break; } } // 2. Precompute LCA/Path Max and Flows dfs_lca_build(1, 0, 0, -1, 0); // Build LCA/Path Max from root 1 dfs_flow_calc(1, 0); // Calculate flows from root 1 // 3. Calculate potential revenue and conflicts node_weights.resize(k_val, 0); std::map<int, std::vector<int>> replaced_to_replacers; // original_id -> list of new_edge ids (0..k-1) for (int i = 0; i < k_val; ++i) { int u = new_edges_input[i].u; int v = new_edges_input[i].v; std::pair<int, int> path_max_info = query_path_max(u, v); int max_c = path_max_info.first; int replaced_original_id = path_max_info.second; if (replaced_original_id != -1 && edge_flow.count(replaced_original_id)) { long long revenue = (long long)max_c * edge_flow[replaced_original_id]; node_weights[i] = revenue; replaced_to_replacers[replaced_original_id].push_back(i); } // Else, revenue remains 0 } // 4. Build conflict graph conflict_adj.resize(k_val); for (auto const& [replaced_id, replacer_indices] : replaced_to_replacers) { if (replacer_indices.size() > 1) { for (size_t i = 0; i < replacer_indices.size(); ++i) { for (size_t j = i + 1; j < replacer_indices.size(); ++j) { int u_idx = replacer_indices[i]; int v_idx = replacer_indices[j]; conflict_adj[u_idx].push_back(v_idx); conflict_adj[v_idx].push_back(u_idx); } } } } // 5. Solve MWIS is_selected.assign(k_val, false); max_revenue_found = 0; solve_mwis(0, 0); // 6. Output result std::cout << max_revenue_found << std::endl; return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...