[GESP202406 六级] 二叉树(含视频)

视频讲解:GESP202406 六级 二叉树-信息学奥赛GESP等级考试真题解析

一、原题

题目描述

小杨有一棵包含 n 个节点的二叉树,且根节点的编号为 1。这棵二叉树任意一个节点要么是白色,要么是黑色。之后小杨会对这棵二叉树进行 q 次操作,每次小杨会选择一个节点,将以这个节点为根的子树内所有节点的颜色反转,即黑色变成白色,白色变成黑色。

小杨想知道 q 次操作全部完成之后每个节点的颜色。

输入格式

第一行一个正整数 n,表示二叉树的节点数量。

第二行 (n−1) 个正整数,第 i(1≤i≤n−1)个数表示编号为 (i+1) 的节点的父亲节点编号,数据保证是一棵二叉树。

第三行一个长度为 n 的 01 串,从左到右第 i(1≤i≤n)位如果为 0,表示编号为 i 的节点颜色为白色,否则为黑色。

第四行一个正整数 q,表示操作次数。

接下来 q 行每行一个正整数 ai​(1≤ai​≤n),表示第 i 次操作选择的节点编号。

输出格式

输出一行一个长度为 n 的 01 串,表示 q 次操作全部完成之后每个节点的颜色。从左到右第 i(1≤i≤n) 位如果为 0,表示编号为 i 的节点颜色为白色,否则为黑色。

输入输出样例

输入 #1

复制代码
6
3 1 1 3 4
100101
3
1
3
2

输出 #1

复制代码
010000

说明/提示

样例解释

第一次操作后,节点颜色为:011010

第二次操作后,节点颜色为:000000

第三次操作后,节点颜色为:010000

数据范围
子任务编号 得分 n q 特殊条件
1 20 ≤10^5 ≤10^5 对于所有 i≥2,节点 i 的父亲节点编号为 i−1
2 40 ≤1000 ≤1000
3 40 ≤10^5 ≤10^5

对于全部数据,保证有 n,q≤105。

二、做题思路

1)填充数据

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
char ans[100005];
int c[100005];
int main(){
	//1)填充数据
	//1.1)确定结点数量n
	int n;cin>>n;
	//1.2)填充2至n的父节点
	for(int i=2;i<=n;i++){
		int t;cin>>t;
		g[t].push_back(i);
	} 
	//1.3)填充n个节点初始颜色
	for(int i=1;i<=n;i++) cin>>ans[i];
	//1.4)确定操作次数q
	int q;cin>>q;
	//1.5)确定q次操作的节点
	while(q--){
		int t;cin>>t;
		c[t]++;
	}
	return 0;
}

2)深搜 计算当前节点操作次数 确定颜色

2.1-2)从根结点1开始搜 , 搜索每个节点

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
char ans[100005];
int c[100005];
//2.2)搜索每个节点
void dfs(int x,int now){
	for(auto it:g[x]){
		dfs(it,now);
	}
}
int main(){
	//1)填充数据
	//...
	//2)深搜 计算当前节点操作次数 确定颜色
	//2.1)从根结点1开始搜 
	dfs(1,0);
	return 0;
}

2.3)计算当前节点操作次数(受父节点影响,需继承之前的操作次数)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
char ans[100005];
int c[100005];
//2.2)搜索每个节点
void dfs(int x,int now){
	//2.3)计算当前节点操作次数
	now+=c[x];
	for(auto it:g[x]){
		dfs(it,now);
	}
}
int main(){
	//1)填充数据
	//...
	//2)深搜 计算当前节点操作次数 确定颜色
	//2.1)从根结点1开始搜 
	dfs(1,0);
	return 0;
}

2.4)确定颜色(操作次数奇数,颜色取反,否则不变 )

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
char ans[100005];
int c[100005];
//2.2)搜索每个节点
void dfs(int x,int now){
	//2.3)计算当前节点操作次数
	now+=c[x];
	//2.4)确定颜色
	//操作次数奇数,颜色取反,否则不变 
	if(now%2==1) ans[x]=!(ans[x]-'0')+'0'; 
	for(auto it:g[x]){
		dfs(it,now);
	}
}
int main(){
	//1)填充数据
	//...
	//2)深搜 计算当前节点操作次数 确定颜色
	//2.1)从根结点1开始搜 
	dfs(1,0);
	return 0;
}

3)输出每个节点的颜色

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
char ans[100005];
int c[100005];
//2.2)搜索每个节点
void dfs(int x,int now){
	//2.3)计算当前节点操作次数
	now+=c[x];
	//2.4)确定颜色
	//操作次数奇数,颜色取反,否则不变 
	if(now%2==1) ans[x]=!(ans[x]-'0')+'0'; 
	for(auto it:g[x]){
		dfs(it,now);
	}
}
int main(){
	//1)填充数据
	//...
	//2)深搜 计算当前节点操作次数 确定颜色
	//2.1)从根结点1开始搜 
	dfs(1,0);
	//3)输出每个节点的颜色 
	for(int i=1;i<=n;i++) cout<<ans[i];
	return 0;
}

三、答案

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
char ans[100005];
int c[100005];
//2.2)搜索每个节点
void dfs(int x,int now){
	//2.3)计算当前节点操作次数
	now+=c[x];
	//2.4)确定颜色
	//操作次数奇数,颜色取反,否则不变 
	if(now%2==1) ans[x]=!(ans[x]-'0')+'0'; 
	for(auto it:g[x]){
		dfs(it,now);
	}
}
int main(){
	//1)填充数据
	//1.1)确定结点数量n
	int n;cin>>n;
	//1.2)填充2至n的父节点
	for(int i=2;i<=n;i++){
		int t;cin>>t;
		g[t].push_back(i);
	} 
	//1.3)填充n个节点初始颜色
	for(int i=1;i<=n;i++) cin>>ans[i];
	//1.4)确定操作次数q
	int q;cin>>q;
	//1.5)确定q次操作的节点
	while(q--){
		int t;cin>>t;
		c[t]++;
	}
	//2)深搜 计算当前节点操作次数 确定颜色
	//2.1)从根结点1开始搜 
	dfs(1,0);
	//3)输出每个节点的颜色 
	for(int i=1;i<=n;i++) cout<<ans[i];
	return 0;
}
相关推荐
惊鸿一博1 小时前
Plücker直线_ 用两个三维向量描述一条空间直线
线性代数·算法·直线·几何表示
小道士写程序1 小时前
Rust 中的字符串与切片(String 与 &str)
算法
Tisfy1 小时前
LeetCode 3863.将一个字符串排序的最小操作次数:分类讨论(一次遍历)——简单易懂版
算法·leetcode·字符串·题解·分类讨论
Young Doro2 小时前
从平衡表征到最小充分因果表征:端到端神经网络因果效应估计
算法
0+1112 小时前
算法 --递归
算法·leetcode
打工仔折腾 AI2 小时前
介入式脑机接口的跨尺度解码与闭环调控:从算法落地到后端工程实践
人工智能·后端·python·深度学习·算法·ai agent 实战
凤山老林2 小时前
授权模型只会RBAC?深入 ABAC 授权模型,实现权限判断做成策略引擎
大数据·数据库·算法
starzy19902 小时前
KafkaProducer 源码深度剖析:支撑高吞吐的数据结构设计
大数据·数据结构·kafka
海绵宝宝转agent3 小时前
2026-10-21学习笔记
笔记·学习·算法