树上前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):利用函数式编程的思想使 ...
随机推荐
- 网络ASI
ASIHTTPRequest 基于底层CFNetwork框架,运行效率很高 可惜作者 停止更新,有一些潜在的BUG无人去解决 老项目 ASI + SBJson 只需要用到外面的源文件 ASI还依赖于 ...
- lerna式升级
有段时间没更新博客了,是时候更新一波了. 之前不是vue-next出了吗,然后就去学习了一下,发现整个目录不是那么熟悉了,变成这样了: 于是就这个线索去研究了一下,发下这是用的 lerna + yar ...
- 商品分页查询 ego-prc 实现-easyui
使用 easyui 的 DataGrid 控件实现商品的分页查询,DataGrid 控件提交分页所需要的 page 和rows 参数,后台响应包含总记录数 total 和需要显示的商品对象的集合 ro ...
- MyBatis_多表关联查询_resultMap_单个对象_N+1方式实现
mapper 层 提供 StudentMapper 和 ClazzMapper, StudentMapper 查询所有学生信息, ClazzMapper 根据编号查询班级信息. 再 StudentMa ...
- [Python Basics]下划线变量
夜暗归云绕柁牙,江涵星影鹭眠沙. 行人怅望苏台柳,曾与吴王扫落花. 我平时很常见到的带有下划线的python变量有两种: 前后双下划线,我之前的理解是python程序中的类似meta data的信息, ...
- 统计学习方法与Python实现(一)——感知机
统计学习方法与Python实现(一)——感知机 iwehdio的博客园:https://www.cnblogs.com/iwehdio/ 1.定义 假设输入的实例的特征空间为x属于Rn的n维特征向量, ...
- 【CSS】378- [译]44个 CSS 精选知识点
写在前面 一个周五的晚上,闲来无事整理下自己的 github(经常做收藏党),今天打算都过一遍,发现一个 star很高的项目,里面有大量的 CSS 片段,而且标题很诱人,然后又花了将近1个小时从头到尾 ...
- 【重温基础】17.WebAPI介绍
本文是 重温基础 系列文章的第十七篇. 今日感受:挑战. 系列目录: [复习资料]ES6/ES7/ES8/ES9资料整理(个人整理) [重温基础]1-14篇 [重温基础]15.JS对象介绍 [重温基础 ...
- Sockit 硬件接口编程——点亮一个LED
1.话不多说上代码 #include <stdio.h> #include <stdlib.h> #include <string.h> #include < ...
- Linux系统入门简介<1>
linux系统入门简介 我们为什么要学习Linux? 在介绍Linux的历史前,我想先针对大家如何对Linux的发音说一下.我发现我身边的朋友对Linux的发音大致有这么几种: "里那克斯& ...