树上前k大的包含不重复结点的长链
一棵树,不一定是二叉树,在每个结点最多只属于一条链的情况下,处理出其中最长的前k个的长度。
最近训练赛做到两道题了,有必要总结一下。
不过我不知道是否有更专门的叫法。
借鉴了这位大佬的博客:https://www.cnblogs.com/Aragaki/p/11754534.html
例题1.
2019-2020 ACM-ICPC Brazil Subregional Programming Contest
https://codeforces.com/gym/102346/problem/D
题意就是你要抓一个组织的人,这些组织每个人只知道他直接的一个领导的信息,知道一个人,可以依次向上抓他的领导,给你k次机会,求出能抓住的最多的人数。
显然是一棵树,贪心的找法就是每次找目前来说最长的链,且要考虑结点重复的情况,就需要我们处理出前k大的含不重复结点的长链的长度。
算法就是邻接表存这棵树。不知道为啥我第二题比赛时用前向星存树TLE了,换邻接表就成了。
ans数组记录当前节点子树里的最长链长为多少 dfs到一个节点 就把除了最长链上的儿子的ans全部push到q里,qq里存的就是除了最长链以外,当前结点作为根节点的子节点所组成链的长度。
我们将1号结点作为整棵树的根节点,最后把ans[1],ans[1]就是最长链的长度, push到q里 取最大的k个即可
为什么这么做是正确的 因为优先队列q里存的是每个节点的父亲节点去掉最长链后自己当根节点时子树的最长链长度
#include<bits/stdc++.h>
#define debug(x) cout << #x << ": " << x << endl
typedef long long ll;
using namespace std;
const int MAXN=1e5+;
vector<int> g[MAXN];
int ans[MAXN];
ll a[MAXN];
priority_queue<int> q;
void dfs(int x)
{
priority_queue<int> qq;
ans[x] = ;
for (int v : g[x])
{
dfs(v);
qq.push(ans[v]);
}
if (g[x].size())
{
ans[x] = qq.top() + ;
qq.pop();
while (qq.size())
{
q.push(qq.top());
qq.pop();
}
}
}
int main()
{
int n, k, x;
scanf("%d%d", &n, &k);
for (int i = ; i <= n; i++)
{
scanf("%d", &x);
g[x].push_back(i);
}
ll anser = ;
dfs();
q.push(ans[]);//ans[1]为最长链长度
int sz=q.size();
for(int i=;i<=min(k,sz);++i)
{
int tmp=q.top();
anser += tmp;
q.pop();
}
printf("%I64d\n", anser);
return ;
}
第二题
这个好像没地方补。。。
BAPC 2019 The 2019 Benelux Algorithm Programming Contest
A Appeal to the Audience
题意就是分配k个选手到k个叶子节点,每个选手有能力值,层层battle,观众获得的快乐值就是子节点上几个选手能力值的和,然后晋级的是选手能力值中最大的,成为父节点,求出最终最大的得分,题目保证这棵树正好有k个叶子节点。
理解之后发现就是每个选手都可以有贡献,我们肯定要让优秀的选手从更底层上来,对总分产生更大的贡献。
那么就和上面一题一样,我们需要处理出来k个包含不重复节点的最长链,为什么不重复呢?
因为选手相遇了只能晋级一个,只能让一个对接下来的深度产生贡献。
之后对选手能力值排序,贪心的最大的选手,匹配最深的即可。
注意到,最长链的长度需要-1,因为最长链包含根节点,手玩一下样例就可以知道,包含根节点长度为4的链产生3层贡献,而其他的链都是不包括根节点的,直接乘能力值即可。
同样邻接表存树,1号节点为根节点,由于题给为0号节点开始,每次++编号即可。
#include<bits/stdc++.h>
#define debug(x) cout << #x << ": " << x << endl
typedef long long ll;
using namespace std;
const int MAXN=1e5+;
vector<int> g[MAXN];
int ans[MAXN];
ll a[MAXN];
priority_queue<int> q;
void dfs(int x)
{
priority_queue<int> qq;
ans[x] = ;
for (int v : g[x])
{
dfs(v);
qq.push(ans[v]);
}
if (g[x].size())
{
ans[x] = qq.top() + ;
qq.pop();
while (qq.size())
{
q.push(qq.top());
qq.pop();
}
}
}
int main()
{
int n, k, x;
scanf("%d%d", &n, &k);
for(int i=; i<=k; ++i) scanf("%I64d",&a[i]);
for (int i = ; i <= n; i++)
{
scanf("%d", &x);
x++;
g[x].push_back(i);
}
ll anser = ;
dfs();
q.push(ans[]);//ans[1]为最长链长度
sort(a+,a++k);
int t=k;
//int sz=q.size();
for(int i=;i<=k;++i)
{
//debug(q.top());
int tmp=q.top();
if(i==) tmp--;
anser += (a[t--]*tmp);
q.pop();
}
printf("%I64d\n", anser);
return ;
}
然后注意到,这里的q.size()就是叶子节点的数量,与k是一样的,第二题就是覆盖全树,全取完。
树上前k大的包含不重复结点的长链的更多相关文章
- poj2104 主席树 区间K大 在线 无修改
关于主席树: 主席树(Chairman Tree)是一种离线数据结构,使用函数式线段树维护每一时刻离散之后的数字出现的次数,由于各历史版本的线段树结构一致,可以相减得出区间信息,即该区间内出现的数字和 ...
- poj2104 划分树 区间K大 在线 无修改
博主sbit....对于高级数据结构深感无力,然后这些东西在OI竟然烂大街了,不搞就整个人都不好了呢. 于是我勇猛的跳进了这个大坑 ——sbit 区间K大的裸题,在线,无修改. 可以用归并树(\(O( ...
- Permutation UVA - 11525(值域树状数组,树状数组区间第k大(离线),log方,log)(值域线段树第k大)
Permutation UVA - 11525 看康托展开 题目给出的式子(n=s[1]*(k-1)!+s[2]*(k-2)!+...+s[k]*0!)非常像逆康托展开(将n个数的所有排列按字典序排序 ...
- Codeforces Gym101505G:Orchard Division(扫描线+线段树第k大)
题目链接 题意 给出一个m*m的地图,上面有n个点,现在需要用一个自定义面积的矩形笼罩住恰好n/2个点,并且这个矩形需要有一个点在至少一个角落上,问这个矩形最小的面积是多少. 思路 有点类似于扫描线. ...
- hdu 5102 树上前k短路径长度和
http://acm.hdu.edu.cn/showproblem.php?pid=5102 给一棵树,求出所有节点的距离中前k小的路径长度和 由于路径长度的定义为两点之间的边的个数,所有遍历1~n- ...
- FZU 2237 中位数 主席树 树上k大
#include <cstdio> #include <cstring> #include <queue> #include <set> #includ ...
- POJ2104-- K-th Number(主席树静态区间第k大)
[转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249 无修改的区间第K大 我们先考虑简化的问题:我们要询问整个区间内的第K大.这样我们对值域建线段 ...
- 【大杀器】利用划分树秒杀区间内第k大的数
最近看了一道题,大概就是给出一个序列,不断询问其子区间内第k大的数,下面是个截图 绕了一圈没找到中文版题目,if(你是大佬) then 去看截图:else{我来解释:给出一个整数n,和一个整数m,分别 ...
- 静态区间第k大(主席树)
POJ 2104为例(主席树入门题) 思想: 可持久化线段树,也叫作函数式线段树,也叫主席树(高大上). 可持久化数据结构(Persistent data structure):利用函数式编程的思想使 ...
随机推荐
- 4、Docker 镜像构建
Docker 镜像构建 构建分为两种 手动构建 自动构建dockerfile 手动构建 首先启动一个Centos 容器,然后在容器中安装一个nginx [root@node ~]# docker ru ...
- 鲲鹏性能优化十板斧之前言 | 鲲鹏处理器NUMA简介与性能调优五步法
鲲鹏处理器NUMA简介 随着现代社会信息化.智能化的飞速发展,越来越多的设备接入互联网.物联网.车联网,从而催生了庞大的计算需求.但是功耗墙问题以功耗和冷却两大限制极大的影响了单核算力的发展.为了满足 ...
- 快速理解spark-on-k8s中的external-shuffle-service
[摘要] external-shuffle-service是Spark里面一个重要的特性,有了它后,executor可以在不同的stage阶段动态改变数量,大大提升集群资源利用率.但是这个特性当前在k ...
- Eclipse for Tricore 的安装方法
1.安装JDK32位版 2.安装Eclipse for Tricore 32位版(应该也只有32位的) 3.OK(如果打开Tricore提示找不到JDK的话,在网上搜索如何配置JDK,修改环境变量) ...
- vue-socket.io使用教程与踩坑记录
全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/12018866.html,多谢,=.=~ (如果对你有帮助的话请帮我点个赞啦) 请先允许我狠狠吐个 ...
- 利用python实现dll依赖关系导出
#说明:遍历rootdir目录下所有dll,导出每个dll依赖的dll信息到dstdir目录下 # 配合NotePad++打开所有txt,搜索,可快速定位到某dll被依赖的所有dll文件 import ...
- luogu P4302 [SCOI2003]字符串折叠
题目描述 折叠的定义如下: 一个字符串可以看成它自身的折叠.记作S = S X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) = SSSS-S(X个S). 如果A = A', B = ...
- React中autoComplete="off" 失效
Turning Off Autocomplete in Chrome with React tl;dr Add a hidden input with an arbitrary value attri ...
- HDU1561 The more ,The better (树形背包Dp)
ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物.但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先 ...
- 写入Apache Hudi数据集
这一节我们将介绍使用DeltaStreamer工具从外部源甚至其他Hudi数据集摄取新更改的方法, 以及通过使用Hudi数据源的upserts加快大型Spark作业的方法. 对于此类数据集,我们可以使 ...