「十二省联考2019」 春节十二响

Description

给出一颗有根树,每个点有一个权值,现在要求将这些点划分成若干个集合,要求在同一个集合中的点不存在祖先—后代关系,规定一个集合的代价为集合中所有点的权值的最大值,问所有划分方案中代价和最小的是多少

Solution

考虑首先对这颗树进行重链剖分,然后对于对于一条重链,用一个大根堆去维护它链上的节点及其子树中的所有节点的集合代价,那么在合并两条重链时,就直接贪心从两个堆中取出最大值比较下大小进行合并就好了

Code

 //Created Time:2020年05月12日 星期二 08时57分29秒
 #include <queue>
 #include <vector>
 #include <cstdio>
 #include <cstring>
 #include <iostream>
 #include <algorithm>
 #define N 200005
 
 using namespace std;
 
 int n;
 int fa[N], a[N], son[N], sz[N];
 
 vector<int> e[N];
 priority_queue<int> Q[N];
 
 void dfs1(int);
 void dfs2(int, int);
 
 int main(){
 #ifndef ONLINE_JUDGE
     freopen("a.in", "r", stdin);
     freopen("a.out", "w", stdout);
 #endif
  scanf("%d", &n);
  for(int i = 1; i <= n; ++i)
  scanf("%d", a + i);
  for(int i = 2; i <= n; ++i)
  scanf("%d", fa + i), e[fa[i]].push_back(i);
  dfs1(1); dfs2(1, 1);
  long long res = 0;
  while(!Q[1].empty())
  res += Q[1].top(), Q[1].pop();
  cout << res << endl;
  return 0;
 }
 
 void dfs1(int u){
  sz[u] = 1;
  for(auto v : e[u]){
  dfs1(v); sz[u] += sz[v];
  if(sz[son[u]] < sz[v])
  son[u] = v;
  }
  return ;
 }
 
 void dfs2(int u, int top){
  if(!son[u]) return Q[top].push(a[u]), void();
  dfs2(son[u], top);
  priority_queue<int> tmp;
  for(auto v : e[u]){
  if(v == son[u]) continue;
  dfs2(v, v);
  while(!Q[top].empty() && !Q[v].empty()){
  int x = Q[top].top(), y = Q[v].top();
  Q[top].pop(); Q[v].pop();
  tmp.push(max(x, y));
  }
  while(!Q[v].empty()) Q[top].push(Q[v].top()), Q[v].pop();
  while(!tmp.empty()) Q[top].push(tmp.top()), tmp.pop();
  }
  Q[top].push(a[u]);
  return ;
 }



posted @ 2020-06-10 16:13  Roal_L  阅读(144)  评论(0编辑  收藏  举报