Luogu5290 [十二省聯考2019] 春節十二響 【貪心】【堆】


題目分析:

對於一個根,假設我們對每個子樹分別求出了一種答案,那么怎么合並答案是最小的呢?

首先考慮這些答案里面最大的那個數字,它肯定要融合其它組里面的最大數字。以此類推

所以最好的合並方式是,每個子樹的答案從大到小排序,然后依次合並。

然后我們會發現,這個其實是可以划分子問題的,因為如果某個子樹不按照這種方式划分,那么必然不會使得某個位置變小另一個位置變大,只會使得相應位置變大。

所以按子樹划分下去,把堆合並就行。

代碼:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 202000;
 5 
 6 int n;
 7 int a[maxn],f[maxn];
 8 vector <int> g[maxn];
 9 int pts[maxn],num;
10 priority_queue<int,vector<int>,less<int> > pq[maxn],hc;
11 
12 void read(){
13     scanf("%d",&n);
14     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
15     for(int i=2;i<=n;i++) scanf("%d",&f[i]),g[f[i]].push_back(i); 
16 }
17 
18 void dfs(int now){
19     for(int i=0;i<g[now].size();i++) {
20     dfs(g[now][i]);
21     if(pq[pts[now]].size() < pq[pts[g[now][i]]].size())
22         pts[now] = pts[g[now][i]];
23     }
24     for(int i=0;i<g[now].size();i++){
25     if(pts[now] != pts[g[now][i]]){
26         while(pq[pts[g[now][i]]].size()){
27         int k = pq[pts[now]].top(); pq[pts[now]].pop();
28         int z = pq[pts[g[now][i]]].top(); pq[pts[g[now][i]]].pop();
29         hc.push(max(k,z));
30         }
31         while(!hc.empty()){pq[pts[now]].push(hc.top());hc.pop();}
32     }
33     }
34     if(pts[now] == 0) pts[now] =++num;
35     pq[pts[now]].push(a[now]);
36 }
37 
38 int main(){
39     read();
40     dfs(1);
41     long long ans = 0;
42     while(!pq[pts[1]].empty()){
43     ans += pq[pts[1]].top();
44     pq[pts[1]].pop();
45     }
46     printf("%lld\n",ans);
47     return 0;
48 }

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com