还有33天就要高考了,我在干啥……

题目概述

一棵有根树,每个节点有权值。

要求把所有节点分成组,具有祖先-后代关系的两个节点不能被分到同一组。

每一组的代价是所包含的节点的最大权值,最小化所有组的代价之和。

题解

想了半天的树剖也没想出来,放弃梦想去看题解……(你怎么不先想想部分分啊喂)

发现是启发式合并。

考虑一条链(1号节点在中间的某个位置)咋做。

这棵树的形状是1号节点下面挂着两条长链。隶属于同一条链的节点都不能放在一组。那么只需要把两条链各自的最大值节点放到一组,各自的次大值节点放到一组……一条链被用完了,另一条中剩下的节点分别自成一组。

那么假如1号节点下面有更多条链呢?只需要合并完两条之后再把第三条合并进去,方法和上面相同。

那么整棵树其实也dfs然后对每个节点这么合并所有的儿子就好了。这个找最大值再找次大值再找次次大值……的数据结构,显然用堆。

如何优化复杂度呢?启发式合并。把每个节点的儿子按照对应堆的大小排个序,然后把小的往大的合并。这个启发式合并吧,和我们熟知的那个启发式合并还不太一样,复杂度非常神奇,合并两个堆之后新堆的大小是原先较大堆的大小,而合并需要的push、pop操作数是原先较小堆的大小。相当于把较小堆的每个元素以\(O(\log n)\)的复杂度“删去”了,“删去”以后就不再对总复杂度造成代价了。总共最多“删去”n个节点,每次复杂度\(O(\log n)\),总复杂度\(O(n\log n)\)。

写代码的时候会陷入僵局——若要保证复杂度正确,对应堆最大的那个儿子不能对复杂度做出贡献,也就是你不能动它的堆。然而全合并完之后,那个堆里面的东西要存在父亲节点对应的堆里面。昨天晚上我懵逼半天之后选择去睡觉,今天上数学课走神的时候才想到咋整……给每个节点设置个“id”,表示对应的堆的编号,这样堆存的地方不用动,交换父亲和最大儿子的id即可。

代码

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
bool op = 0;
char c;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
} const int N = 200005;
int n, id[N];
ll w[N], ans;
vector <int> son[N];
priority_queue <int> que[N]; bool cmp(int a, int b){
return que[id[a]].size() > que[id[b]].size();
}
void dfs(int u){
vector <int> buf;
for(auto v: son[u])
dfs(v);
sort(son[u].begin(), son[u].end(), cmp);
for(auto v: son[u]){
if(que[id[u]].empty()) swap(id[u], id[v]);
else{
while(!que[id[v]].empty()){
int u_top = que[id[u]].top(), v_top = que[id[v]].top();
que[id[u]].pop(), que[id[v]].pop();
buf.push_back(max(u_top, v_top));
}
for(auto x: buf)
que[id[u]].push(x);
buf.clear();
}
}
que[id[u]].push(w[u]);
} int main(){ read(n);
for(int i = 1; i <= n; i++)
read(w[i]), id[i] = i;
for(int i = 2, f; i <= n; i++)
read(f), son[f].push_back(i);
dfs(1);
while(!que[id[1]].empty())
ans += que[id[1]].top(), que[id[1]].pop();
write(ans), enter; return 0;
}

LuoguP5290 [十二省联考2019]春节十二响 | 启发式合并的更多相关文章

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

    题目地址:P5290 [十二省联考2019]春节十二响 骗分方法 如果你实在一点思路也没有,暴力都不会打,那么请考虑一下骗分. 方法一 输出所有 \(M\) 的和. 期望得分:0分. 实际还有5分 方 ...

  2. P5290 [十二省联考2019]春节十二响(堆+启发式合并)

    P5290 [十二省联考2019]春节十二响 从特殊到一般 我们先看链的情况. 我们把点$1$左右的两条子链分别扔入堆里 每次取出两个堆的最大值,把答案累加上更大的那个(另一堆为空则直接加上去). 那 ...

  3. Luogu P5290 / LOJ3052 【[十二省联考2019]春节十二响】

    联考Day2T2...多亏有这题...让我水了85精准翻盘进了A队... 题目大意: 挺简单的就不说了吧...(这怎么简述啊) 题目思路: 看到题的时候想了半天,不知道怎么搞.把样例画到演草纸上之后又 ...

  4. 【堆的启发式合并】【P5290】[十二省联考2019]春节十二响

    Description 给定一棵 \(n\) 个节点的树,点有点权,将树的节点划分成多个集合,满足集合的并集是树的点集,最小化每个集合最大点权之和. Limitation \(1~\leq~n~\le ...

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

    这题是最近看到的今年省选题中最良心的一道了吧 看题+想题+写题都可以在0.5h内解决,送分含义明显啊 首先理解了题意后我们很快就能发现两个点如果要被分在一段那么必须在它们的祖先处合并 首先我们考虑下二 ...

  6. Luogu5290 十二省联考2019春节十二响(贪心+启发式合并)

    考虑链的做法,显然将两部分各自从大到小排序后逐位取max即可,最后将根计入.猜想树上做法相同,即按上述方式逐个合并子树,最后加入根.用multiset启发式合并即可维护.因为每次合并后较小集合会消失, ...

  7. [LOJ3052] [十二省联考 2019] 春节十二响

    题目链接 LOJ:https://loj.ac/problem/3052 洛谷:https://www.luogu.org/problemnew/show/P5290 BZOJ:https://www ...

  8. luogu P5290 [十二省联考2019]春节十二响 优先队列_启发式合并

    思维难度不大,在考上上写的启发式合并写错了,只拿了 60 pts,好难过QAQ 没什么太难的,在考场上想出链的部分分之后很容易就能想到正解.没错,就是非常短的启发式合并.注意一下,写的要漂亮一点,否则 ...

  9. 【题解】Luogu P5290 [十二省联考2019]春节十二响

    原题传送门 每个点维护一个堆,表示这个点及其子树所需的每段内存的空间 搜索时从下向上做启发式合并堆中信息,最后根节点堆中所有内存空间之和就是答案 #include <bits/stdc++.h& ...

随机推荐

  1. 聊一聊 bootstrap 的轮播图插件

    今天做工作的时候,轻车熟路的做完,又用到了bootstrap的轮播图,觉得有必要安利一下这个插件,如果你需要的轮播图.功能不需要太炫酷,那么bootstrap的插件是你的首要选择. 使用方式 引入js ...

  2. C# Mutex to make sure only one unique application instance started

    static void MutexDemo2() { string assName = Assembly.GetEntryAssembly().FullName; bool createdNew; u ...

  3. django10-form表单组件

    1.form组件的主要功能 生成页面的HTML标签和样式 ,将前端form表单的代码放在后端生成!! 对用户提交的数据进行校验(正则) 自动生成错误信息 保留上次输入信息 2.form组件常用字段与插 ...

  4. CSS animation 属性

    定义和用法 animation属性是下列属性的一个缩写属性: animation-name animation-duration animation-timing-function animation ...

  5. docker环境无法执行jmap -heap 56命令

    很奇怪的问题,但是jstack可以执行 解决方法: docker 内部使用jmap 需要启动容器时候配置权限:docker run --privileged=true  --cap-add=SYS_P ...

  6. QT信号槽连接语法总结

    信号槽是 Qt 框架引以为豪的机制之一. 所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal).这种触发是没有目的的,类似广播.如果 ...

  7. AI反欺诈:千亿的蓝海,烫手的山芋|甲子光年

    不久前,一家业界领先的机器学习公司告诉「甲子光年」:常有客户带着迫切的反欺诈需求主动找来,但是,我们不敢接. 难点何在? 作者|晕倒羊 编辑|甲小姐 设计|孙佳栋 生死欺诈 企业越急速发展,越容易产生 ...

  8. MySQL数据库(三)锁机制

    MyISAM默认使用表级锁,不支持行级锁 InnoDB默认使用行级锁,也支持表级锁 表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率最高,并发度最低. 行级锁:开销大,加锁慢:会出现 ...

  9. 渗透测试学习 二十、 其他漏洞汇总之PHP相关漏洞

    大纲: PHP相关漏洞 JSP相关漏洞 其他漏洞汇总 PHP相关漏洞 文件包含漏洞 php://input等伪协议利用 代码执行漏洞 变量覆盖漏洞 文件包含漏洞 程序开发人员一般会把重复使用的函数写到 ...

  10. Lnmp架构部署动态网站环境.2019-7-2-1.1

    一.Mysql简介 Mysql数据库: 1.社区版 2.商业版 3.cluster集群 Mysql安装方式 1.编译安装 2.yum/rpm 3.二进制包,直接解压,无需编译 二.Mysql安装部署 ...