视频讲解:GESP202312 六级 工作沟通-信息学奥赛GESP等级考试真题解析
一、原题
题目描述
某公司有 N 名员工,编号从 0 至 N−1。其中,除了 0 号员工是老板,其余每名员工都有一个直接领导。我们假设编号为 i 的员工的直接领导是 fi。
该公司有严格的管理制度,每位员工只能受到本人或直接领导或间接领导的管理。具体来说,规定员工 x 可以管理员工 y,当且仅当 x=y,或 x=fy,或 x 可以管理 fy。特别地,0 号员工老板只能自我管理,无法由其他任何员工管理。
现在,有一些同事要开展合作,他们希望找到一位同事来主持这场合作,这位同事必须能够管理参与合作的所有同事。如果有多名满足这一条件的员工,他们希望找到编号最大的员工。你能帮帮他们吗?
输入格式
第一行一个整数 N,表示员工的数量。
第二行 N−1 个用空格隔开的正整数,依次为 f1,f2,...fN−1。
第三行一个整数 Q,表示共有 Q 场合作需要安排。
接下来 Q 行,每行描述一场合作:开头是一个整数 m(2≤m≤N),表示参与本次合作的员工数量;接着是 m 个整数,依次表示参与本次合作的员工编号(保证编号合法且不重复)。
保证公司结构合法,即不存在任意一名员工,其本人是自己的直接或间接领导。
输出格式
输出 Q 行,每行一个整数,依次为每场合作的主持人选。
输入输出样例
输入 #1
5
0 0 2 2
3
2 3 4
3 2 3 4
2 1 4
输出 #1
2
2
0
输入 #2
7
0 1 0 2 1 2
5
2 4 6
2 4 5
3 4 5 6
4 2 4 5 6
2 3 4
输出 #2
2
1
1
1
0
说明/提示
样例解释 1
对于第一场合作,员工 3,4 有共同领导 2 ,可以主持合作。
对于第二场合作,员工 2 本人即可以管理所有参与者。
对于第三场合作,只有 0 号老板才能管理所有员工。
数据范围
对于 50% 的测试点,保证 N≤50。
对于所有测试点,保证 3≤N≤300,Q≤100。
二、做题思路
1)构造树

cpp
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
int main(){
//1)构造树
int n;cin>>n;
for(int i=1;i<=n-1;i++){
int t;cin>>t;
g[t].push_back(i);
}
return 0;
}
2)深搜,记录每个结点的层数和祖宗结点

cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
map<int,bool> storage;
int deep;
}tree[310];//存储每个结点的高度 和 所有祖宗
map<int,vector<int>>g;
map<int,vector<int>>d_storage;
void dfs(int x,int deep,map<int,bool> storage){
//2.2)计算高度,存储到高度数组
tree[x].deep=deep;
d_storage[deep].push_back(x);
//2.3)加入当前结点
storage[x]=1;
//2.4)记录之前传递的祖宗
tree[x].storage=storage;
//2.5)循环所有儿子 递归
for(auto it:g[x]){
dfs(it,deep+1,storage);
}
}
int main(){
//1)构造树
int n;cin>>n;
for(int i=1;i<=n-1;i++){
int t;cin>>t;
g[t].push_back(i);
}
//2)深搜,记录每个结点的层数和祖宗结点
//2.1)从0开始
map<int,bool> temp_storage;
dfs(0,1,temp_storage);
return 0;
}
3)填充q次查询

cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
map<int,bool> storage;
int deep;
}tree[310];//存储每个结点的高度 和 所有祖宗
map<int,vector<int>>g;
map<int,vector<int>>d_storage;
void dfs(int x,int deep,map<int,bool> storage){
//...
}
int main(){
//1)构造树
//...
//2)深搜,记录每个结点的层数和祖宗结点
//2.1)从0开始
map<int,bool> temp_storage;
dfs(0,1,temp_storage);
//3)填充q次查询
//3.1)确定查询次数q
int q;cin>>q;
for(int i=1;i<=q;i++){
//3.2)填充m名员工
int m;cin>>m;
int a[310];
for(int j=1;j<=m;j++) cin>>a[j];
}
return 0;
}
4)找出所有可能的父节点,找出最大

cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
map<int,bool> storage;
int deep;
}tree[310];//存储每个结点的高度 和 所有祖宗
map<int,vector<int>>g;
map<int,vector<int>>d_storage;
void dfs(int x,int deep,map<int,bool> storage){
//...
}
int main(){
//1)构造树
//...
//2)深搜,记录每个结点的层数和祖宗结点
//2.1)从0开始
map<int,bool> temp_storage;
dfs(0,1,temp_storage);
//3)填充q次查询
//3.1)确定查询次数q
int q;cin>>q;
for(int i=1;i<=q;i++){
//3.2)填充m名员工
int m;cin>>m;
int a[310];
for(int j=1;j<=m;j++) cin>>a[j];
//4)找出所有可能的父节点,找出最大
//4.1)找最小高度
int minn=n;
for(int j=1;j<=m;j++)
minn=min(tree[a[j]].deep,minn);
//4.2)从高度1 到 最小高度
int maxx=0;
for(int j=1;j<=minn;j++){
//4.3)循环当前高度所有结点
for(auto it:d_storage[j]){
//4.4)判断m名员工是否都有该祖宗
bool flag=true;
for(int h=1;h<=m;h++){
if( tree[a[h]].storage[it]==0 ){
flag=false;
break;
}
}
//4.5)找最大的节点
if(flag) maxx=max(maxx,it);
}
}
//4.6)输出结果
cout<<maxx<<"\n";
}
return 0;
}
三、答案
cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
map<int,bool> storage;
int deep;
}tree[310];
map<int,vector<int>>g;
map<int,vector<int>>d_storage;
void dfs(int x,int deep,map<int,bool> storage){
//2.2)计算高度,存储到高度数组
tree[x].deep=deep;
d_storage[deep].push_back(x);
//2.3)加入当前结点
storage[x]=1;
//2.4)记录之前传递的祖宗
tree[x].storage=storage;
//2.5)循环所有儿子 递归
for(auto it:g[x]){
dfs(it,deep+1,storage);
}
}
int main(){
//1)构造树
int n;cin>>n;
for(int i=1;i<=n-1;i++){
int t;cin>>t;
g[t].push_back(i);
}
//2)深搜,记录每个结点的层数和祖宗结点
//2.1)从0开始
map<int,bool> temp_storage;
dfs(0,1,temp_storage);
//3)填充q次查询
//3.1)确定查询次数q
int q;cin>>q;
for(int i=1;i<=q;i++){
//3.2)填充m名员工
int m;cin>>m;
int a[310];
for(int j=1;j<=m;j++) cin>>a[j];
//4)找出所有可能的父节点,找出最大
//4.1)找最小高度
int minn=n;
for(int j=1;j<=m;j++)
minn=min(tree[a[j]].deep,minn);
//4.2)从高度1 到 最小高度
int maxx=0;
for(int j=1;j<=minn;j++){
//4.3)循环当前高度所有结点
for(auto it:d_storage[j]){
//4.4)判断m名员工是否都有该祖宗
bool flag=true;
for(int h=1;h<=m;h++){
if( tree[a[h]].storage[it]==0 ){
flag=false;
break;
}
}
//4.5)找最大的节点
if(flag) maxx=max(maxx,it);
}
}
//4.6)输出结果
cout<<maxx<<"\n";
}
return 0;
}