Submission #1308248

#TimeUsernameProblemLanguageResultExecution timeMemory
1308248orzorzorzFireworks (APIO16_fireworks)C++20
0 / 100
2 ms568 KiB
/** * APIO 2016 - Fireworks (煙火表演) * 解法:Slope Trick + Small-to-Large Merging (啟發式合併) * 時間複雜度:O((N+M) log^2 (N+M)) */ #include <iostream> #include <vector> #include <queue> #include <algorithm> using namespace std; const int MAXN = 300005; // 鄰接表:存儲子節點 vector<int> adj[MAXN]; // 邊權:edge_weight[i] 表示節點 i 與其父節點之間的邊權 long long edge_weight[MAXN]; // 每個節點維護一個 Max Heap (用 priority_queue 實作) priority_queue<long long>* pq[MAXN]; // 記錄所有邊權的總和 long long total_edge_sum = 0; void dfs(int u) { // 初始化當前節點的 heap pq[u] = new priority_queue<long long>(); // 遍歷所有子節點 for (int v : adj[u]) { dfs(v); // --- Small-to-Large Merging (啟發式合併) --- // 確保 u 的 heap 總是比較大的那個,以減少搬移次數 if (pq[u]->size() < pq[v]->size()) { swap(pq[u], pq[v]); } // 將 v (較小的 heap) 中的元素全部轉移到 u (較大的 heap) while (!pq[v]->empty()) { pq[u]->push(pq[v]->top()); pq[v]->pop(); } // 釋放 v 的記憶體 delete pq[v]; } // 處理當前節點的函數變化 // 1. 如果是葉子節點 (除了根節點外) if (adj[u].empty() && u != 1) { long long w = edge_weight[u]; // 葉子的函數是 |x - w|,轉折點為 w, w pq[u]->push(w); pq[u]->push(w); pq[u]->pop(); } // 2. 如果是內部節點 (非根) else if (u != 1) { long long w = edge_weight[u]; int deg = adj[u].size(); // 彈出 deg - 1 個最大值,將斜率修正為 1 // 因為每條邊只能貢獻 1 的斜率變化 while (deg > 1) { pq[u]->pop(); deg--; } // 取出斜率為 0 的區間端點 [L, R] long long R = pq[u]->top(); pq[u]->pop(); long long L = pq[u]->top(); pq[u]->pop(); // 加上邊權 w 並放回堆中 (平移函數) pq[u]->push(R + w); pq[u]->push(L + w); } // 3. 如果是根節點 else { int deg = adj[u].size(); // 根節點不需要考慮父邊,只需找到最小值 // 最小值在斜率為 0 處取得,將所有斜率 > 0 的部分彈出 // 堆中目前有 deg 個斜率 > 0 的轉折點 while (deg > 0) { pq[u]->pop(); deg--; } // 計算答案 // 最小代價 = 總邊權 - 剩餘轉折點之和 while (!pq[u]->empty()) { total_edge_sum -= pq[u]->top(); pq[u]->pop(); } } } int main() { // 加速 I/O ios_base::sync_with_stdio(false); cin.tie(NULL); int N, M; if (!(cin >> N >> M)) return 0; // 讀取輸入 // 題目輸入從第 2 行開始,描述節點 2 到 N+M 的父節點 p 和邊權 w 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; } dfs(1); cout << total_edge_sum << 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...