首页 > 其他分享 >Luogu P5290 [十二省联考 2019] 春节十二响

Luogu P5290 [十二省联考 2019] 春节十二响

时间:2023-09-03 12:00:18浏览次数:34  
标签:head int Luogu 十二 tot MxN 集合 联考

Luogu P5290 [十二省联考 2019] 春节十二响

题目链接

题目大意

一颗有根树, 有点权, 把点分成若干个集合, 要求每个集合内不包含祖先关系, 求集合的最大值的和的最小值.

做题思路

考虑合并两个集合, 我们只需要不停把分别吧两个集合的最大值取出取max加入答案, 再把大集合剩下的内容加进答案.

通过直接使用之前的堆, 不用开新的堆, 可以做到 \(O(min(S_1,S_2))\)

我们对于每个节点, 直接合并所有子树, 然后加入这个节点单独成一个集合.

复杂度计算

我们发现, 把一个节点的所有子树合并的时间复杂度正好相当于整个子树的大小减去最大的儿子的大小.

所以,这个算法可以理解为一种树上启发式合并,时间复杂度为 \(O(n\log^2n)\) , 其中一个\(\log\)是堆,一个\(\log\)是启发式合并

核心代码

namespace WangManhe{
    using namespace Basic_Data_Structure;
    const int MxN=200000;
    
    int n;
    int head[MxN+5],nxt[2*MxN+5],to[2*MxN+5],tot;
    int siz[MxN+5],son[MxN+5];
    int cost[MxN+5],id[MxN+5];
    Heap<int>H[MxN+5];

    void AddEdge(int u,int v){
        to[++tot]=v;
        nxt[tot]=head[u];
        head[u]=tot;
    }
    void DFS1(int p,int fa){
        for(int i=head[p];i;i=nxt[i]){
            if(to[i]!=fa){
                DFS1(to[i],p);
                Heap<int>T;
                if(H[id[p]].size()<H[id[to[i]]].size()){
                    swap(id[p],id[to[i]]);
                }
                while(!H[id[to[i]]].empty()){
                    T.push(max(H[id[to[i]]].top(),H[id[p]].top()));
                    H[id[to[i]]].pop();H[id[p]].pop();
                }
                while(!T.empty()){
                    H[id[p]].push(T.top());
                    T.pop();
                }
            }
        }
        H[id[p]].push(cost[p]);
    }
    void Main(int Case){
        int u,v;
        scanf("%lld",&n);
        for(int i=1;i<=n;i++){
            scanf("%lld",&cost[i]);
            id[i]=i;
        }
        for(int i=2;i<=n;i++){
            scanf("%lld",&u);
            AddEdge(u,i);
            AddEdge(i,u);
        }
        DFS1(1,0);
        int ans=0;
        while(!H[id[1]].empty()){
            ans+=H[id[1]].top();
            H[id[1]].pop();
        }
        printf("%lld\n",ans);
    }
    void Initialize(){
        
    }
}

标签:head,int,Luogu,十二,tot,MxN,集合,联考
From: https://www.cnblogs.com/WangManhe/p/17674827.html

相关文章

  • 【LuoGu】1351 联合权值
    [NOIP2014提高组]联合权值题目描述无向连通图\(G\)有\(n\)个点,\(n-1\)条边。点从\(1\)到\(n\)依次编号,编号为\(i\)的点的权值为\(W_i\),每条边的长度均为\(1\)。图上两点\((u,v)\)的距离定义为\(u\)点到\(v\)点的最短距离。对于图\(G\)上的点对\((u,v......
  • 【题解】Luogu[P7706] 「Wdsr-2.7」文文的摄影布置
    Link一道很有意思的线段树题。第一步分析,我们要求最大的\(a_i+a_k-\min{(b_j)}\),事实上我们可以直接省去这个\(\min\)因为要最大化这个东西,选出来的\(b_j\)必然是最小的,所以原题转化为给定\(l,r\)求\(\max{(a_i-b_j+a_k)}\)其中\(i<j<k\)。第二步分析,我们发现这是一......
  • 【题解】Luogu-P2482 SDOI2010 猪国杀
    写了\(358\)行,\(11.94\mathrm{KB}\),有这么几个地方写挂了:反猪决斗一定选主猪。游戏结束判定是主猪死亡或全部反猪死亡。决斗可能被反杀,之后不能再出牌。点击查看代码#include<bits/stdc++.h>usingnamespacestd;intn,m;charCh[3];queue<char>Deck;in......
  • [DS记录] P6623 [省选联考 2020 A 卷] 树
    题目传送门\(\rmTrie\)树的一些牛逼应用异或和是可以用\(\rm01-Trie\)维护的。我们发现对于一个点\(x\),需要需要维护\(x\)子树的所有点的异或和,这可以理解成\(\rmTrie\)树的合并。同时有一个\(d(y,x)\)的存在,其实考虑\(\rmdfs\)的过程,相当于先合并所有子节点的......
  • Android并发编程高级面试题汇总(含详细解析 十二)
    Android并发编程高级面试题汇总最全最细面试题讲解持续更新中......
  • Prometheus监控实战系列十二:配置告警规则
    在上篇的文章中,我们通过Grafana实现了监控可视化。而对于运维监控而言,除了监控展示以外,另一个重要的需求无疑就是告警了。良好的告警可以帮助运维人员及时的发现问题,处理问题并防范于未然,是运维工作中不可或缺的重要手段。 在Prometheus的架构中,告警功能由PrometheusServer和A......
  • [十二省联考 2019] 春节十二响
    题目链接。题意给出一棵有\(n\)个节点的树,要求你将集合\(\{1,2,\dots,n\}\)划分成若干个子集,使得没有子集拥有节点对满足两个元素在树上是祖孙关系。你需要最小化子集的最大值之和。先考虑带有启发性的子任务\(4\)(树是一颗链)。具体来说,树有以下两种形态:根节点是链的......
  • 代码随想录算法训练营第二十二天| 235. 二叉搜索树的最近公共祖先 701.二叉搜索树
      235. 二叉搜索树的最近公共祖先    卡哥建议:相对于 二叉树的最近公共祖先 本题就简单一些了,因为 可以利用二叉搜索树的特性。   题目链接/文章讲解:https://programmercarl.com/0235.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%B......
  • NumPy学习挑战第十二关-数组操作
    Numpy数组操作Numpy中包含了一些函数用于处理数组,大概可分为以下几类:1、修改数组形状函数 描述reshape 不改变数据的条件下修改形状flat 数组元素迭代器flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组ravel 返回展开数组(1)numpy.reshapenumpy.reshape函数......
  • [九省联考 2018 D1T3] 秘密袭击
    考虑转化为求\(\gei\)的权值个数\(\gek\)的联通块数量。设\(f(u,i,j)\)表示\(u\)子树内含\(u\)联通块内权值\(\gei\)的有\(j\)个的方案数,\(g(u,i,j)\)维护子树的和,也就是最终答案。发现转移非常简单所以可以写成生成函数:\[F(u,i)=x^{[d_u\gei]}\prod_{(u,......