【十二省联考】春节十二响【贪心】【堆】【启发式合并】
生活随笔
收集整理的這篇文章主要介紹了
【十二省联考】春节十二响【贪心】【堆】【启发式合并】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
題意:給一棵nnn個點帶點權的樹,要求把點分成若干部分,有祖孫關系的點不能在同一部分。求每個部分最大值 的和 的最小值。
n≤2×105n \leq 2\times 10^5n≤2×105
由鏈的部分得到啟發,每個點用一個堆來維護,合并兩個時不斷彈出兩個堆頂并在最后加入較大值直到一個為空。合并完后加入根,最終的和就是答案。
這樣復雜為兩邊的大小之和。
發現合并是把較少的丟到較大的中,可以啟發式合并,即少的取完后丟回較多的。可以用指針實現。
這樣復雜度是O(nlog?n)O(n\log n)O(nlogn)
好像和長鏈剖分本質相同
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <queue> #include <vector> #define MAXN 200005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } typedef long long ll; typedef priority_queue<int> pq; pq *q[MAXN]; int val[MAXN]; vector<int> e[MAXN]; void dfs(int u) {q[u]=new pq;for (int i=0;i<(int)e[u].size();i++){dfs(e[u][i]);if (q[u]->size()<q[e[u][i]]->size()) swap(q[u],q[e[u][i]]);vector<int> tmp;while (!q[e[u][i]]->empty()) tmp.push_back(max(q[u]->top(),q[e[u][i]]->top())),q[u]->pop(),q[e[u][i]]->pop();for (vector<int>::iterator it=tmp.begin();it!=tmp.end();++it) q[u]->push(*it);}q[u]->push(val[u]); } int main() {int n=read();for (int i=1;i<=n;i++) val[i]=read();for (int i=2;i<=n;i++) e[read()].push_back(i);dfs(1);ll ans=0;while (!q[1]->empty()) ans+=q[1]->top(),q[1]->pop();printf("%lld\n",ans);return 0; }總結
以上是生活随笔為你收集整理的【十二省联考】春节十二响【贪心】【堆】【启发式合并】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 滴耳油能治耳鸣吗
- 下一篇: 【NOI online 2】游戏【二项式