/**
* APIO 2016 - Fireworks
* 55+ Point Solution (STL Priority Queue + Small-to-Large Merging)
*/
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN = 300005;
// Adjacency list: store children indices
vector<int> adj[MAXN];
// Edge weights: weight[i] is weight of edge between i and its parent
long long edge_weight[MAXN];
// Priority Queue to store breakpoints for each node
priority_queue<long long> pq[MAXN];
// Number of leaves in the subtree
int num_leaves[MAXN];
void dfs(int u) {
// Base Case: If u is a leaf (no children)
if (adj[u].empty()) {
num_leaves[u] = 1;
// Leaf cost function is |x - 0|, breakpoints at 0, 0
// Slope changes from -1 to 0 at 0, and 0 to 1 at 0
pq[u].push(0);
pq[u].push(0);
return;
}
num_leaves[u] = 0;
for (int v : adj[u]) {
dfs(v);
num_leaves[u] += num_leaves[v];
// Small-to-Large Merging
// Always merge the smaller queue into the larger one to keep complexity low
if (pq[u].size() < pq[v].size()) {
swap(pq[u], pq[v]);
}
// Move all elements from child v to parent u
while (!pq[v].empty()) {
pq[u].push(pq[v].top());
pq[v].pop();
}
}
// Logic for Internal Nodes (excluding Root for a moment)
// We want the slope to eventually reach 1.
// The slope starts at -num_leaves[u].
// Each breakpoint increases slope by 1.
// To stop at slope 1, we need (num_leaves[u] + 1) breakpoints.
// Pop the largest elements (steepest positive slopes) until size fits.
// Note: We perform the edge shift logic ONLY if we are NOT the root yet,
// or we treat the root specially afterwards.
// The standard Slope Trick usually shifts at the child before merging,
// or shifts at the node before passing up. Here we process node u completely.
// To process the edge above u (connecting u to parent):
// 1. Reduce max slope to 1.
while (pq[u].size() > num_leaves[u] + 1) {
pq[u].pop();
}
// 2. Pop top two points (L and R), shift them by edge weight W, push back.
long long r = pq[u].top(); pq[u].pop();
long long l = pq[u].top(); pq[u].pop();
pq[u].push(l + edge_weight[u]);
pq[u].push(r + edge_weight[u]);
}
int main() {
// Optimize I/O operations
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n, m;
if (!(cin >> n >> m)) return 0;
long long total_edge_sum = 0;
// Input format: For i from 2 to N+M
// P_i (Parent), W_i (Weight)
for (int i = 2; i <= n + m; i++) {
int p;
long long w;
cin >> p >> w;
adj[p].push_back(i);
edge_weight[i] = w;
total_edge_sum += w;
}
// Run DFS from the switch (Node 1)
// Note: The DFS above adds the edge weight of 'u' at the end of 'u' processing.
// However, Node 1 (Root) has no parent edge.
// We need to be careful. The logic inside DFS adds edge_weight[u].
// For root, edge_weight[1] is 0 (global array init), so adding 0 doesn't hurt logic
// BUT root requires slope 0, not 1.
// Let's adjust DFS slightly or handle root separately.
// Simpler: Run DFS for children of root, merge into root, then handle root logic manually.
// Re-implementation of Main Loop for Root logic correctness:
// We will call a specific DFS that handles the shift internally.
// Let's modify the DFS call slightly to be pure.
// We can just use the DFS function defined above, but for the Root (Node 1),
// we must undo the "slope 1" logic because Root needs slope 0.
// Actually, simpler to just implement the logic inside DFS with a check.
// Let's rewrite the DFS loop in main to be explicit:
for (int v : adj[1]) {
dfs(v);
num_leaves[1] += num_leaves[v];
if (pq[1].size() < pq[v].size()) swap(pq[1], pq[v]);
while (!pq[v].empty()) {
pq[1].push(pq[v].top());
pq[v].pop();
}
}
// Final processing for Root (Node 1)
// Root needs to end at slope 0 (optimality condition).
// Start slope is -num_leaves[1].
// Target slope is 0.
// We need num_leaves[1] breakpoints.
while (pq[1].size() > num_leaves[1]) {
pq[1].pop();
}
// Calculate Answer
// Min Cost = Sum of all edge weights - Sum of retained breakpoints
// (This is a derived property of the slope trick for this specific problem)
long long retained_sum = 0;
while (!pq[1].empty()) {
retained_sum += pq[1].top();
pq[1].pop();
}
cout << total_edge_sum - retained_sum << endl;
return 0;
}
| # | 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... |