zoukankan      html  css  js  c++  java
  • [长链剖分][优先队列] LibreOJ #3052 春节十二响

    题目大意

    • 给一棵树,点有点权,要求把所有节点分成若干个集合,使得同一集合中任意两点不存在祖先关系,且每一集合的最大点权的和最小

    题解

    • 考虑递归处理,假设当前节点的两棵子树都已处理好,那么合并两棵子树的方式为最大值和最大值合并,次大值和次大值合并
    • 可以用长链剖分+优先队列来优化到O(nlogn)

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <queue>
     5 using namespace std;
     6 const int N=200010;
     7 int n,tot,cnt,sz,a[N],head[N],id[N],son[N],deep[N],tmp[N];
     8 struct edge{int to,from;}e[N];
     9 priority_queue<int>Q[N];
    10 long long ans;
    11 void insert(int x,int y){ e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; }
    12 void pre(int x)
    13 {
    14     deep[x]=1;
    15     for (int i=head[x];i;i=e[i].from) pre(e[i].to),deep[x]=max(deep[x],deep[e[i].to]+1);
    16     for (int i=head[x];i;i=e[i].from) if (deep[x]==deep[e[i].to]+1) son[x]=e[i].to;
    17 }
    18 void dfs(int x)
    19 {
    20     if (son[x]) dfs(son[x]),id[x]=id[son[x]];
    21     for (int i=head[x];i;i=e[i].from) 
    22         if (e[i].to!=son[x])
    23         {
    24             dfs(e[i].to),tot=0;
    25             while (!Q[id[e[i].to]].empty()) tmp[++tot]=max(Q[id[x]].top(),Q[id[e[i].to]].top()),Q[id[x]].pop(),Q[id[e[i].to]].pop();
    26             while (tot) Q[id[x]].push(tmp[tot]),tot--;
    27         }
    28     if (!id[x]) id[x]=++sz;
    29     Q[id[x]].push(a[x]);
    30 }
    31 int main()
    32 {
    33     scanf("%d",&n);
    34     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    35     for (int i=2,x;i<=n;i++) scanf("%d",&x),insert(x,i);
    36     pre(1),dfs(1);
    37     while (!Q[id[1]].empty()) ans+=Q[id[1]].top(),Q[id[1]].pop();
    38     printf("%lld",ans);
    39 }
  • 相关阅读:
    BZOJ2034 【2009国家集训队】最大收益
    「PKUSC2018」最大前缀和
    「PKUSC2018」真实排名
    【FJOI2016】建筑师
    【FJOI2014】最短路径树问题
    【HNOI2007】紧急疏散
    【TJOI2015】线性代数
    【SDOI2017】新生舞会
    POJ2079 Triangle
    【SDOI2011】工作安排
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11193343.html
Copyright © 2011-2022 走看看