D - Project Presentation(DFS序+倍增LCA)
You are given a tree that represents a hierarchy in a company, where the parent of node u is their direct manager.
Each employee is assigned a project, and multiple employees can be assigned to the same project. When it is time for the presentation of the ith project, all employees u that are assigned that project and their direct and indirect managers must attend the presentation (u and their manager and their manager's manager and so on until the CEO).
Find for each project the number of people attending its presentation.
The first line of input is n and m (1 ≤ m ≤ n ≤ 106), the number of employees and the number of projects, respectively.
The second line of input contains n integers ai (1 ≤ ai ≤ m), where ai is the project assigned to the ith employee. It is guaranteed that each project has at least one employee assigned to it.
The third line of input contains n integers pi (0 ≤ pi ≤ n), where pi is the direct manager of the ith employee. If pi = 0, then the ith
employee is the CEO and does not have a manager. It is guaranteed that
there is only one CEO, and this CEO is a direct or indirect manager of
all other employees.
Output
Output m integers, where the ith integer is the number of people attending the presentation of the ith project.
Example
6 4
1 2 4 3 2 4
0 1 1 3 3 2
1 4 3 4
题解:首先根据题意建树,每个节点有对应的任务(1~m),如果一个人处理i任务,那么他所有的祖先都得参与到当中,对于每一个任务,求参与到其中的人的数量。
首先DFS序跑图,得到每个节点的入时间序,时间序对应的原节点,深度,走2^0步得到的节点。
然后对于每一个任务:假设其中有x个人执行这个任务,我们首先将其按DFS序从小到大排序,然后有对应公式:sum+=dep[i]-dep[LCA(i-1,i)]。
那么就该想如何实现这个过程了,下面是用的vector存储:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=;
int w[maxn],x,root,cnt;
int Start[maxn],End[maxn],dep[maxn],par[][maxn],Rev[maxn];
vector<int>G[maxn],vv[maxn],ans;
void DFS(int u,int pre,int d)
{
par[][u]=pre;//u向上走2^0走到pre节点
dep[u]=d;//u的深度
Start[u]=++cnt;//DFS序对应值
Rev[cnt]=u;//将其反过来转换为原来的节点
for(int i=;i<G[u].size();i++){
DFS(G[u][i],u,d+);
}
End[u]=cnt;
}
int LCA(int u,int v)
{
if(dep[u]>dep[v])swap(u,v);
for(int k=;k<;k++){//让u和v走到同一深度
if((dep[v]-dep[u])>>k&){//这里简单理解下就是将u和v的距离用二进制表示,每一位1将其变为0
v=par[k][v];
}
}
if(u==v)return u;
for(int k=;k>=;k--){
if(par[k][u]!=par[k][v]){
u=par[k][u];
v=par[k][v];
}
}
return par[][u];
}
int main()
{
ios::sync_with_stdio();
int n,m;
cin>>n>>m;
for(int i=;i<=n;i++)cin>>w[i];
for(int i=;i<=n;i++){
cin>>x;
if(x!=){
G[x].push_back(i);
}
else
root=i;
}
DFS(root,-,);
for(int k=;k<;k++){//预处理par数组
for(int v=;v<=n;v++){
if(par[k][v]==-)par[k+][v]=-;
else par[k+][v]=par[k][par[k][v]];
}
}
for(int i=;i<=n;i++){
vv[w[i]].push_back(Start[i]);
}
for(int i=;i<=m;i++){
sort(vv[i].begin(),vv[i].end());//按照DFS序递增排序,是为了不重复答案
int sum=;
for(int j=;j<vv[i].size();j++){
if(j==)sum+=dep[Rev[vv[i][j]]];
else sum+=dep[Rev[vv[i][j]]]-dep[LCA(Rev[vv[i][j-]],Rev[vv[i][j]])];
}
ans.push_back(sum);
}
for(int i=;i<ans.size();i++)cout<<ans[i]<<" ";
cout<<endl;
return ;
}
D - Project Presentation(DFS序+倍增LCA)的更多相关文章
- P3703 [SDOI2017]树点涂色 LCT维护颜色+线段树维护dfs序+倍增LCA
\(\color{#0066ff}{ 题目描述 }\) Bob有一棵\(n\)个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点 ...
- luogu3320 寻宝游戏 (dfs序+倍增lca+set)
一定是从随便某个点开始,然后按着dfs序的顺序跑一圈是最好的 所以说,新加一个点x,就减少了dis(pre,next),增加了dis(pre,x),dis(x,nxt) 删掉一个点同理 这个可以用se ...
- 洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- dfs序 + RMQ = LCA
dfs序是指你用dfs遍历一棵树时,每个节点会按照遍历到的先后顺序得到一个序号.然后你用这些序号,可以把整个遍历过程表示出来. 如上图所示,则整个遍历过程为1 2 3 2 4 5 4 6 4 2 1 ...
- bzoj 2819 Nim(BIT,dfs序,LCA)
2819: Nim Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1596 Solved: 597[Submit][Status][Discuss] ...
- bzoj3306: 树(dfs序+倍增+线段树)
比较傻逼的一道题... 显然求子树最小值就是求出dfs序用线段树维护嘛 换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论. 如果询问的x是根就直接输出整棵树的最小值. 如果询问的x是 ...
- CF 208E - Blood Cousins dfs序+倍增
208E - Blood Cousins 题目:给出一棵树,问与节点v的第k个祖先相同的节点数有多少个. 分析: 寻找节点v的第k个祖先,这不就是qtree2简化版吗,但是怎么统计该祖先拥有多少个深度 ...
- 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增
3545: [ONTAK2010]Peaks Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1202 Solved: 321[Submit][Sta ...
- 蓝皮书:异象石 【dfs序+lca】
题目详见蓝皮书[算法竞赛:进阶指南]. 题目大意: 就是给你一颗树,然后我们要在上面进行三种操作: 1.标记某个点 或者 2.撤销某个点的标记 以及 3.询问标记点在树上连通所需的最短总边 ...
随机推荐
- promise核心技术 1 实例对象/函数对象
一个程序员要在看到代码的语法同时判断数据类型 知道语法是基础 基础才能延伸功能 //一行代码 a()[0]() // a() 首先推断出a是一个函数 //a()[0] 判断a函数的返回值是一个数组 ...
- Palette 的使用
Palette有什么用? Palette主要功能就是可以从图片中提取各种与颜色有关的元素.通过使用 Palette ,我们可以很轻松的实现界面风格的统一. Palette的使用很简单,首先你可以从gi ...
- Arduino LiquidCrystal库函数中文对照
我之所以会试试看LCD+Shield,一是因为我本来就有这块板,但一直不会用,第二个原因则是Arduino+Cookbook这本书.O’Reilly的这本手册对你在Arduino实践中的各种问题(几乎 ...
- hook鼠标
library dllMouse; uses SysUtils, Classes, UnitHookDLL in 'UnitHookDLL.pas', UnitHookConst in 'UnitHo ...
- SQL基础教程(第2版)第8章 SQL高级处理:8-1 窗口函数
第8章 SQL高级处理:8-1 窗口函数 ● 窗口函数可以进行排序.生成序列号等一般的聚合函数无法实现的高级操作.● 理解PARTITION BY和ORDER BY这两个关键字的含义十分重要. ■什么 ...
- Django1.11基础视图
Django视图 路由命名与reverse反解析 在项目urls中的include函数,使用namespace参数定义路由命名空间 url(r'^',incude('book.urls',namesp ...
- linux环境java程序cpu爆表问题查证
1.top命令查找导致cup爆表的进程 2. top -H -p10832 (10832是Java进程的PID)命令找出了具体的线程 3.使用用命令 jstack 10832> jstack.t ...
- 神经网络 参数计算--直接解析CKPT文件读取
1.tensorflow的模型文件ckpt参数获取 import tensoflow as tf from tensorflow.python import pywrap_tensorflow mod ...
- 洛谷P1002 过河卒(动态规划)
题目描述 棋盘上 AA 点有一个过河卒,需要走到目标 BB 点.卒行走的规则:可以向下.或者向右.同时在棋盘上 CC 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点.因此称之为 ...
- Bezier曲线的实现——de Casteljau算法
这学期同时上了计算机图形学和计算方法两门课,学到这部分的时候突然觉得de Casteljau递推算法特别像牛顿插值,尤其递推计算步骤很像牛顿差商表. 一开始用伯恩斯坦多项式计算Bezier曲线的时候, ...