视频讲解:GESP202503 六级 树上漫步-信息学奥赛GESP等级考试真题解析
一、原题
题目描述
小 A 有一棵 n 个结点的树,这些结点依次以 1,2,⋯,n 标号。
小 A 想在这棵树上漫步。具体来说,小 A 会从树上的某个结点出发,每一步可以移动到与当前结点相邻的结点,并且小 A 只会在偶数步(可以是零步)后结束漫步。
现在小 A 想知道,对于树上的每个结点,从这个结点出发开始漫步,经过偶数步能结束漫步的结点有多少个(可以经过重复的节点)。
输入格式
第一行,一个正整数 n。
接下来 n−1 行,每行两个整数 ui,vi,表示树上有⼀条连接结点 ui 和结点 vi 的边。
输出格式
一行,n 个整数。第 i 个整数表示从结点 i 出发开始漫步,能结束漫步的结点数量。
输入输出样例
输入 #1
cpp
3
1 3
2 3
输出 #1
cpp
2 2 1
输入 #2
cpp
4
1 3
3 2
4 3
输出 #2
cpp
3 3 1 3
说明/提示
对于 40% 的测试点,保证 1≤n≤10^3。
对于所有测试点,保证 1≤n≤2×10^5。
二、做题思路
1)填充数据

cpp
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
int main(){
//1)填充数据
//1.1)确定节点数量n
int n;cin>>n;
//1.2)填充n-1条边的链接情况
for(int i=1;i<=n-1;i++){
int u,v;cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
return 0;
}
2)深搜:计算奇/偶数高度的节点数量
cpp
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
bool vis[200005];
int d[200005];
int total[2];
//2.2)深搜每个结点
void dfs(int x,int deep){
//2.4)计算奇数偶数结点数量
total[deep%2]++;
//2.5)标记当前结点的高度
d[x]=deep;
vis[x]=1;
for(auto it:g[x]){
if(vis[it]==0){
//2.3)计算当前结点高度
dfs(it,deep+1);
}
}
}
int main(){
//1)填充数据
//...
//2)深搜:计算奇/偶数高度的节点数量
//2.1)从结点1开始深搜
dfs(1,1);
return 0;
}
3)输出结果
cpp
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
bool vis[200005];
int d[200005];
int total[2];
//2.2)深搜每个结点
void dfs(int x,int deep){
//2.4)计算奇数偶数结点数量
//....
//2.5)标记当前结点的高度
//...
//2.3)计算当前结点高度
//...
}
int main(){
//1)填充数据
//...
//2)深搜:计算奇/偶数高度的节点数量
//2.1)从结点1开始深搜
dfs(1,1);
//3)输出结果
for(int i=1;i<=n;i++){
//结点高度是奇数,输出奇数总数
if(d[i]%2==1) cout<<total[1]<<" ";
//结点高度是偶数,输出奇数偶数
else cout<<total[0]<<" ";
}
return 0;
}
三、答案
cpp
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
bool vis[200005];
int d[200005];
int total[2];
//2.2)深搜每个结点
void dfs(int x,int deep){
//2.4)计算奇数偶数结点数量
total[deep%2]++;
//2.5)标记当前结点的高度
d[x]=deep;
vis[x]=1;
for(auto it:g[x]){
if(vis[it]==0){
//2.3)计算当前结点高度
dfs(it,deep+1);
}
}
}
int main(){
//1)填充数据
//1.1)确定节点数量n
int n;cin>>n;
//1.2)填充n-1条边的链接情况
for(int i=1;i<=n-1;i++){
int u,v;cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
//2)深搜:计算奇/偶数高度的节点数量
//2.1)从结点1开始深搜
dfs(1,1);
//3)输出结果
for(int i=1;i<=n;i++){
//结点高度是奇数,输出奇数总数
if(d[i]%2==1) cout<<total[1]<<" ";
//结点高度是偶数,输出奇数偶数
else cout<<total[0]<<" ";
}
return 0;
}

