树上前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):利用函数式编程的思想使 ...
随机推荐
- [学习笔记] [数据分析] 01.Python入门
1.安装Python与环境配置 ① ② 安装pip以及利用pip安装Python库 2.Anaconda安装 conda list 要在root环境下 3.常用数据分析库 ① Numpy 安装:con ...
- Scheme实现数字电路仿真(1)——组合电路
EDA是个很大的话题,本系列只针对其中一小部分,数字电路的仿真,叙述一点概念性的东西,并不会过于深入,这方面的内容实则是无底洞.本系列并不是真的要做EDA,按照SICP里的相关内容,采用Lisp的方言 ...
- phpStorm自动生成___jb_tmp___文件
把这个去掉就可以了
- 使用Jq实现弹出层
对于前端程序员来说,弹出层是经常用到的,下面我叫大家如何用实现JQuery实现弹出层的效果,代码如下: CSS:弹出层的效果 .mask { position: absolute; top: 0px; ...
- 【如何让代码变“高级”(二)】-这样操作值得一波666(Java Stream)(这么有趣)
[如何让代码变“高级”(二)]-这样操作值得一波666(Java Stream)(这么有趣) 开发中的代码 在开发中的代码是不是很常见这样的代码: 这样的? for循环取元素取值 List<Us ...
- Multiplication Game
Description Alice and Bob are in their class doing drills on multiplication and division. They quick ...
- 1、在aspx.cs后台Response.Write()跳转路径,打开新窗口
1.Response.Write()打开新窗口 Response.Write(" <script type='text/JavaScript'>window.open('&quo ...
- 统计学习方法与Python实现(一)——感知机
统计学习方法与Python实现(一)——感知机 iwehdio的博客园:https://www.cnblogs.com/iwehdio/ 1.定义 假设输入的实例的特征空间为x属于Rn的n维特征向量, ...
- AcWing 291.蒙德里安的梦想
题目:蒙德里安的梦想 链接:(蒙德里安的梦想)[https://www.acwing.com/problem/content/293/] 题意:求把N * M的棋盘分割成若干个1 * 2的长方形,有多 ...
- Obeject.hasOwnProperty
对象{ }要用for-in遍历对象内的属性,通过hasOwnProperty判断属性是否是对象本身的,而不是原型上的 数组[ ]可以通过forEach来遍历