树上前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):利用函数式编程的思想使 ...
随机推荐
- salesforce lightning零基础学习(十六) 公用组件之 获取字段label信息
我们做的项目好多都是多语言的项目,针对不同国家需要展示不同的语言的标题.我们在classic中的VF page可谓是得心应手,因为系统中已经封装好了我们可以直接在VF获取label/api name等 ...
- Python 报错集合
1.django_error:HINT: Add or change a related_name argument to the definition for...报错, 详情见: https:// ...
- C 可变参数函数的本质
C语言支持定义可变参数的函数,方法是在函数的参数列表最后加上 " ... ",代表变长的参数列表,例如: void Func(int num, ...) { } 需要注意 “... ...
- java之扩展运算符
java中的扩展运算符为+=.-=./=.%=.*= 当使用扩展运算符时,变量在参与赋值运算时会把结果自动强制转换为当前变量的类型,比如: public class Test{ public stat ...
- 微信SDK接入报undefined symbol错误
按照官方SDK接入 编译后报如下错误 是因为没有link libc++库导致的.
- Java修炼——递归算法的俩个实例
1.是输出指定文件目录下的所以子目录以及文件 2.使用递归算算法:1!+2!+3!+4!+5!+-+n!(计算阶乘累加) package com.bjsxt.recurison; import jav ...
- Exponial
Description Everybody loves big numbers (if you do not, you might want to stop reading at this point ...
- 纯手工搭建K8s(单节点)
准备说明: 因为为纯手动搭建,所以针对安装时需要的一些安装包需提前下载好 cfssl_linux-amd64. cfssljson_linux-amd64. cfssl-certinfo_linux- ...
- 开发 Laravel 扩展的基本流程
创建一个空的laravel项目 composer create-project --prefer-dist laravel/laravel pkg 在新建的 laravel 项目中建立如下目录 qia ...
- H5中被废弃的标签
<br>换行,已经被<p>标签进行替换 <hr>画线 <font> <b>,<u>,<i>,<s>:加粗 ...