P10722 [GESP202406 六级] 二叉树

从GESP真题解析二叉树核心算法:数组模拟与递归遍历实战 二叉树是数据结构与算法中的核心概念,它以节点和边构成的层次化结构,高效地支持数据的组织与检索。其基本原理在于每个节点最多拥有两个子节点,通过递归遍历(如前序、中序、后序)或迭代遍历(如层序)可以访问和处理所有节点。这一特性使其在搜索、排序、表达式求值等场景中具有极高的技术价值。在编程竞赛和等级认证(如GESP)的实战场景中,面对二叉树问题,**数组模拟**存储结构因其编码简洁、避免内存管理而成为高效选择,结合**递归深度优先搜索(DFS)** 计算深度等指标,能快速将理论转化为可运行的C++代码,解决从节点 阅读详情

记录121

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
vector<int> ch[MAXN];// 邻接表存储树结构,ch[i] 存放节点 i 的所有子节点编号
int op[MAXN],init_col[MAXN],fin_col[MAXN];
// op[i]记录节点i被直接操作的次数;init_col[i]存初始颜色;fin_col[i]存最终颜色
// DFS深度优先搜索函数:u是当前遍历到的节点,par_f是从根到当前节点父节点的累计翻转次数
void dfs(int u,int par_f){
	int total_f=par_f+op[u];// 当前节点的总翻转次数 = 祖先传递下来的翻转次数 + 自己被直接操作的次数
	if(total_f%2==1) fin_col[u]=1-init_col[u];// 如果总翻转次数是奇数,颜色取反(0变1,1变0)
	else fin_col[u]=init_col[u];// 如果总翻转次数是偶数,颜色保持不变
	for(int v:ch[u]) dfs(v,total_f);// 递归遍历所有的子节点v,将当前的总翻转次数传递给下一代
} 
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,q;// n为节点数量,q为操作次数
	cin>>n;// 读入二叉树的节点数量 n
	for(int i=2;i<=n;i++){// 从第2个节点开始读入,因为根节点1没有父亲
		int par; // 临时变量,用于接收当前节点的父亲编号
		cin>>par;// 读入编号为 i 的节点的父亲节点编号
		ch[par].push_back(i);// 建立父子关系,把节点 i 加入其父亲 par 的子节点列表中
	}
	string col_str;// 定义字符串,用于接收长度为 n 的 01 串
	cin>>col_str;// 读入初始颜色字符串
	for(int i=1;i<=n;i++) init_col[i]=col_str[i-1]-'0';
	// 将字符串中的字符转换为数字存入数组(字符串下标从0开始,节点编号从1开始,减去字符'0'得到真实数值)
	cin>>q;// 读入操作次数 q
	for(int i=1;i<=q;i++){// 循环 q 次,处理每一次操作
		int node;// 临时变量,用于接收被操作的节点编号
		cin>>node;// 读入本次操作选择的节点编号
		op[node]++;// 将该节点被直接操作的次数加一(利用奇偶性,不需要立刻修改整棵子树)
	}
	dfs(1,0);// 从根节点(编号为1)开始进行 DFS,初始时祖先传递下来的翻转次数为 0
	for(int i=1;i<=n;i++) cout<<fin_col[i];// 依次输出每个节点的最终颜色
	return 0;//结束程序 
}

前言

我是一名专注信奥赛(CSP-J/S、NOIP)的教练。

  • 如果你觉得这篇题解对你有帮助,欢迎点击关注我的优快云账号,我会持续更新高质量算法解析。
  • 我深知算法思维的构建远比单纯通过题目更重要,本系列题解不局限于AC代码的堆砌,而是致力于拆解题目背后的逻辑链条与核心知识点
  • 备赛路上若遇瓶颈,欢迎随时评论或私信,我将甄选典型疑难问题,通过视频讲解或撰写专项文章的形式,为你提供深度答疑。

题目传送门https://www.luogu.com.cn/problem/P10722


核心思路分析

这是一道经典的树形结构问题,如果采用暴力的方式(每次操作都遍历子树进行颜色反转),在数据规模达到 10^5 时必然会超时。本题的核心在于“延迟更新”和“状态传递”的思想。

1. 翻转的奇偶性本质

  • 对一个节点的颜色进行两次反转,等于没有操作。因此,我们完全不需要关心一个节点被反转了多少次,只需要关心它被反转的次数是奇数还是偶数。这在代码中可以通过简单的 ++ 运算配合 %2 取模来实现。

2. 祖先与后代的关系(自顶向下传递)

  • 题目规定:反转以节点 xx 为根的子树。这意味着,如果一个节点被反转了,那么它的所有子孙节点都会受到这次反转的影响。
  • 因此,对于树上的任意一个节点,它的最终状态由两部分决定:自身的初始颜色 + 从根节点到该节点路径上所有被直接操作的次数总和。

3. DFS 深度优先搜索的应用

  • 我们可以先记录每个节点被直接操作的次数(存入 op[] 数组)。
  • 然后从根节点开始进行一次 DFS。在 DFS 的过程中,维护一个变量 par_f(代表当前节点的父节点及以上所有祖先累计下来的翻转次数)。
  • 到达当前节点 uu 时,总翻转次数 total_f = par_f + op[u]。根据 total_f 的奇偶性,结合初始颜色,就能瞬间算出该节点的最终颜色。
  • 接着,将当前的 total_f 作为新的 par_f 传递给所有的子节点。这样一次 O(N)O(N) 的遍历就完美解决了所有 Q 次操作带来的影响!

代码逐行深度解析

第一部分:头文件、常量定义与全局变量
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
vector<int> ch[MAXN]; // 邻接表存储树结构,ch[i] 存放节点 i 的所有子节点编号
int op[MAXN], init_col[MAXN], fin_col[MAXN];
// op[i]记录节点i被直接操作的次数;init_col[i]存初始颜色;fin_col[i]存最终颜色

解析:这里使用了 vector 数组来构建动态的邻接表,非常适合存储树的父子关系。三个一维数组分工明确:op 负责记录局部操作,init_col 和 fin_col 分别负责状态的起点和终点。

第二部分:DFS 核心递归函数
// DFS深度优先搜索函数:u是当前遍历到的节点,par_f是从根到当前节点父节点的累计翻转次数
void dfs(int u, int par_f){
	int total_f = par_f + op[u]; // 当前节点的总翻转次数 = 祖先传递下来的翻转次数 + 自己被直接操作的次数
	
	if(total_f % 2 == 1) fin_col[u] = 1 - init_col[u]; // 如果总翻转次数是奇数,颜色取反(0变1,1变0)
	else fin_col[u] = init_col[u];                     // 如果总翻转次数是偶数,颜色保持不变
	
	for(int v : ch[u]) dfs(v, total_f); // 递归遍历所有的子节点v,将当前的总翻转次数传递给下一代
} 

解析:这是整个算法的灵魂。通过参数 par_f 实现了状态的自顶向下无缝传递。利用 C++11 的范围 for 循环 for(int v : ch[u]) 使得代码更加简洁优雅。1 - init_col[u] 是一个非常巧妙的位运算替代写法,完美实现了 0 和 1 的反转。

第三部分:主函数入口与 IO 加速
int main(){
	ios::sync_with_stdio(false); // 关闭 C++ 标准输入输出流与 C 标准库的同步
	cin.tie(0);                  // 解除 cin 和 cout 的绑定
	int n, q;                    // n为节点数量,q为操作次数
	cin >> n;                    // 读入二叉树的节点数量 n

解析:面对高达 10^5级别的数据量,标准的 cin/cout 可能会因为底层缓冲区的刷新导致超时。这两行加速代码是应对大数据量输入输出的标配。

第四部分:建树与读取初始颜色
	for(int i = 2; i <= n; i++){ // 从第2个节点开始读入,因为根节点1没有父亲
		int par;                 // 临时变量,用于接收当前节点的父亲编号
		cin >> par;              // 读入编号为 i 的节点的父亲节点编号
		ch[par].push_back(i);    // 建立父子关系,把节点 i 加入其父亲 par 的子节点列表中
	}
	string col_str;              // 定义字符串,用于接收长度为 n 的 01 串
	cin >> col_str;              // 读入初始颜色字符串
	for(int i = 1; i <= n; i++) init_col[i] = col_str[i-1] - '0';
	// 将字符串中的字符转换为数字存入数组(字符串下标从0开始,节点编号从1开始,减去字符'0'得到真实数值)

解析:题目给出的是每个节点的父节点,我们通过 ch[par].push_back(i) 将其转化为正向的邻接表。同时,巧妙利用 ASCII 码的特性 col_str[i-1] - '0',将字符 '0'/'1' 快速转换为整型 0/1。

第五部分:处理操作序列与启动 DFS
	cin >> q;                    // 读入操作次数 q
	for(int i = 1; i <= q; i++){ // 循环 q 次,处理每一次操作
		int node;                // 临时变量,用于接收被操作的节点编号
		cin >> node;             // 读入本次操作选择的节点编号
		op[node]++;              // 将该节点被直接操作的次数加一(利用奇偶性,不需要立刻修改整棵子树)
	}
	dfs(1, 0);                   // 从根节点(编号为1)开始进行 DFS,初始时祖先传递下来的翻转次数为 0
	for(int i = 1; i <= n; i++) cout << fin_col[i]; // 依次输出每个节点的最终颜色
	return 0;                    // 结束程序 
}

解析:在处理 Q 次操作时,代码仅仅做了 op[node]++,将时间复杂度从 O(Q×N)O(Q×N) 骤降至 O(Q) 。最后通过一次 O(N) 的 DFS 统合所有信息并输出结果,整体算法的时间复杂度为完美的 O(N+Q),轻松应对极限数据。

gesp(C++六级)(10)洛谷:P10722:[GESP202406 六级] 二叉树 阅读详情

相关推荐

题解:洛谷 P10722 [GESP202406 六级] 二叉树

题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。次操作,每次小杨会选择一个节点,将以这个节点为根的子树内所有节点的颜色反转,即黑色变成白色,白色变成黑色。问题,核心在于利用"子树操作"的层次性,通过 DFS 自顶向下传递操作次数的奇偶性。次操作,每次选择一个节点,将其子树内所有节点颜色反转。的节点的父亲节点编号,数据保证是一棵二叉树。个节点的二叉树,且根节点的编号为。的节点颜色为白色,否则为黑色。的节点颜色为白色,否则为黑色。,表示二叉树的节点数量。

团爸讲算法 236

P10722 [GESP202406 六级] 二叉树 思路

P10722 [GESP202406 六级] 二叉树

2201_75476959的博客 1450

GESP六级真题考点分析和解题思路

本文分析了GESP六级考试的18道真题,涵盖动态规划、树形结构、图论算法等核心考点。重点题目包括下楼梯(动态规划)、工作沟通(LCA算法)、运送物资(网络流)等。试题难度以普及级为主,涉及拓扑排序、树形DP、二分答案等典型算法。备考建议掌握动态规划状态转移、树结构的DFS遍历、图论算法实现等关键技能,并熟悉提供的代码模板(如拓扑排序和树直径计算)。通过系统练习这些高频题型和算法模板,可以有效提升六级考试通过率。

lan_in的博客 776

洛谷 P10722 [GESP202406 六级] 二叉树-普及/提高-

次操作,每次小杨会选择⼀个节点,将以这个节点为根的子树内所有节点的颜色反转,即黑色变成白色,白色变成黑色。这棵二叉树任意⼀个节点要么是白色,要么是黑色。可以用欧拉序,子树上的所有节点的 dfn 序一定在根节点的两次访问顺序之间。次操作全部完成之后每个节点的颜色。的节点的父亲节点编号,数据保证是⼀棵二叉树。个节点的二叉树,且根节点的编号为。次操作全部完成之后每个节点的颜色。的节点颜色为白色,否则为黑色。的节点颜色为白色,否则为黑色。,表示二叉树的节点数量。次操作选择的节点编号。对于全部数据,保证有。

weixin_37253733的博客 982

自动驾驶必备:5分钟搞懂gPTP如何实现μs级时间同步(附开源代码)

本文深入解析了gPTP协议在自动驾驶系统中实现微秒级时间同步的核心机制与工程实践。针对多传感器融合与跨域协同的严苛需求,文章拆解了gPTP的频率同步、对等延迟测量与时间偏移校正三步流程,并提供了基于linuxptp和AVnu gPTP两大开源代码库的实战配置指南与性能评估方法,助力开发者构建高精度、高可靠的车载时间同步网络。

weixin_29211309的博客 170

ROS入门必学导航算法——Navigation

该平台集成了多款无人车底盘,包括履带式、四轮差速、阿克曼、麦克纳姆轮底盘等,以满足不同形式和配置的需求,并搭载了RTK定位系统、双目相机、深度相机和激光雷达等多种传感器,以满足开发者的科研需求。amcl节点接收里程计数据(通过"odom"话题)和激光雷达数据(通常通过"scan"话题),结合已知的地图,实时地估计出机器人在该地图上的位置。在ROS中,这是通过"tf库"变换实现的,通过将传感器数据转换到共同的参考系中,系统可以更容易地集成来自不同传感器的数据,并确保它们在相同的空间和时间范围内可用。

AMOVLAB(阿木实验室) 2910

《P10722 [GESP202406 六级] 二叉树》

摘要 题目描述了一棵有n个节点的二叉树,每个节点有黑白颜色。进行q次操作,每次翻转以某节点为根的子树颜色。最终输出所有节点颜色。输入包括树结构、初始颜色和操作序列。输出为01串表示最终颜色。样例展示了操作过程,数据规模较大(n,q≤1e5)。核心是高效处理子树翻转操作。

Jasmine_llq的博客 215

AutoSAR开发实战:如何用Matlab/Simulink从零搭建SWC组件(附完整代码示例)

本文详细介绍了使用Matlab/Simulink从零开发AutoSAR SWC组件的全流程,包括环境配置、ARXML文件导入、算法模型开发、代码生成与集成验证等关键步骤。通过实战案例和完整代码示例,帮助开发者掌握AutoSAR标准下的软件开发技术,提升汽车电子系统的开发效率。

weixin_29093017的博客 256

洛谷 P10722:[GESP202406 六级] 二叉树 ← dfs + 邻接表 / 链式前向星

● 当一个节点被反转偶数次时,就相当于没反转。题中所陈述的操作“以这个节点为根的子树内所有节点的颜色反转”,含对根结点进行反转。

hnjzsyjyj的专栏 891

如何让Arduino IDE支持你手里的STM32 nucleo开发板

Arduino IDE开发环境在默认情况下不支持STM32 NUCLEO开发板,只有通过添加附加开发板管理包才能使用。目前为止,只有一部分板子支持使用Arduino IDE开发环境进行开发,分别是 Nucleo F207ZG, Nucleo F429ZI, Nucleo F030R8, Nucleo F091RC, Nucleo F103RB, Nucleo F303RE, Nucl...

mzw72188552的专栏 8972

8、鼠疫流行过程的计算机建模介绍

本博文介绍了一种基于概率细胞自动机和蒙特卡罗方法的计算机模型,用于模拟由大沙鼠传播的鼠疫流行过程。结合GIS和遥感技术,该模型能够分析鼠疫在不同聚居地类型和季节变化下的传播特征,揭示了群落密度、分布及流行接触率对鼠疫传播的影响。研究还验证了模型与自然流行过程的一致性,并探讨了鼠疫在宿主数量低谷时的持续机制。模型为鼠疫防控和流行病研究提供了定量分析工具。

x2y3z4a5b的博客 107

打卡信奥刷题(1995)用C++实现信奥 P10722 [GESP202406 六级] 二叉树

题目摘要:给定一棵n个节点的二叉树,每个节点初始为黑或白色。进行q次操作,每次选择节点反转其子树颜色。最后输出所有节点颜色。 解法概述:使用二叉树结构和懒标记技术。通过后序遍历处理反转操作,将标记下传至子节点,避免重复遍历。时间复杂度O(n),适用于大规模数据。

Loge谈信奥--一个专注于信奥人的博客 767

运动想象 (MI) 分类学习系列 (19) : EEG-TransNet

本文提出了一种基于注意力机制的卷积神经网络(EEG-TransNet),用于运动想象脑电图(MI-EEG)解码。该方法创新性地通过平均池化和方差池化提取多模态时间信息,并结合自注意力模块捕获长期依赖关系。消融实验表明,方差池化比最大池化更有效(p<0.05),且注意力模块和卷积编码器对特征判别性至关重要。可视化分析验证了该方法能学习到更具判别性的紧凑特征。该工作为MI-EEG解码提供了新的多尺度时间信息融合视角,代码已开源。

走在深度学习前沿的小宋 360

【GESP2406六级】计算得分 【GESP2406六级】二叉树

【GESP2406六级】计算得分 【GESP2406六级】二叉树

青少年趣味编程 1222

【ArcGIS Pro微课1000例】0022:基于DEM进行流域分析生成流域图

填洼Fill,在进行水文分析后续操作前,首先要对DEM进行填洼,创建无凹陷点的DEM。在ArcGIS中使用的是八方向流量建模(D8算法),工具位于水文分析下的【流向】。填洼需要使用水文分析工具下的【填洼】。确定输入与输出即可。

智慧空间实验室 2755

全面解析量化价值投资多因子模型的原理

明明知道“买便宜的好公司”是价值投资的核心,但面对3000+只A股,如何快速筛选出“便宜又好”的标的?主观判断总被情绪干扰——明明PE很低的股票,买了却不涨;或者因为“感觉”错过牛股?想规模化投资,但手动分析100只股票就要花一周,根本无法覆盖全市场?量化价值投资的多因子模型,正是解决这些问题的钥匙。它将价值投资的核心逻辑(“便宜”“好公司”)转化为可量化的因子,用数学模型替代主观判断,实现系统化筛选、可回测验证、规模化复制的投资决策。为什么多因子模型能有效预测股票收益?

AI天才研究院 1059

202406 GESP 真题与模拟题

202406 GESP 真题与模拟题

青少年趣味编程 2022

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

P15801 [GESP202603 六级] 完全二叉树

该摘要汇总了关于GESP六级考试中完全二叉树的相关学习资源,包括B站视频教程和优快云博客文章。内容涵盖完全二叉树的基本概念、性质、真题解析及编程实现,同时提供GESP各级考试的备考资料链接。这些资源适用于准备GESP认证考试的考生,特别是需要掌握完全二叉树相关知识点的C++六级考生。

青少年趣味编程 345

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

记——那次难忘的GESP六级考试(202603)+编程题题解

本文记录了作者参加GESP六级考试的全过程,重点描述了备考和考试当天的经历。作者详细列出了自己完成的13道编程题目及解题思路,包括DP、贪心、树状数组等算法题,同时也提到未完成的8道题目。考试当天经历了忘带鼠标的意外,利用触控板继续练习。文章还提到选择题涉及动态规划、树遍历等基础知识,整体展现了作者从紧张备考到从容应考的心路历程,以及面对突发状况的应对能力。

2401_84010520的博客 641

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

GESP认证C++编程真题解析 | 202406 六级

其中(N)是节点总数,(h)是树的高度(层数)。这个选项让新节点s的next指向当前的hs,但随后又把hs更新为hs->next,所以最后hs并不是指向新节点s,逻辑上是不正确的。在链式栈中,新的元素总是插入到链表的头部,也就是说,新节点将成为第一个节点,而之前的第一个节点将成为第二个节点。这个选项仅仅是把hs的下一个节点设为s,并没有更新hs本身,s也没有成为新的栈顶,这样会导致链表结构不正确。这种方式利用了完全二叉树的性质,即除了最后一层外,每一层都是满的,并且最后一层的所有节点尽可能靠左排列。

团爸讲算法 691

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 396

【算法拾光】队列|在每个树⾏中找最⼤值 + 最后⼀块⽯头的重量

本文总结两道经典算法题:一是通过层序遍历(BFS)逐层找最大值,利用队列分层处理,每层维护最大值;二是用大根堆(优先队列)模拟石头碰撞过程,每次取最大两块石头,差值重新入堆,直至剩余一块或无石。前者适用于树的层次遍历,后者适合动态获取最值场景。核心思想:队列用于分层遍历,堆用于高效取极值。

wuqingyigexiaoba的博客 185

【算法拾光】链表 哈希表|K个一组翻转链表 + 两数之和

K个一组翻转链表需分段反转,借助哑节点与前驱指针维护连接,避免断链;两数之和利用哈希表实现O(1)查找,空间换时间,高效定位目标组合。前者考察链表指针操作,后者聚焦映射关系构建,均为面试高频题。

wuqingyigexiaoba的博客 335

把 KV Cache 压到 FP4:BitDecoding-FP4 的算法-系统协同设计复盘

长上下文推理卡在KV Cache的显存与带宽上,而现有FP4方案要么精度崩、要么速度废。这篇文章复盘BitDecoding-FP4如何用三个算法补丁加一个系统重构,在B300上把服务吞吐提升2.4–3.0倍,精度几乎不掉。

helloagent的博客 315

排序算法深度笔记(下):非比较类排序的线性突破与工程边界

排序算法时间复杂度额外空间复杂度稳定性是否基于比较选择排序O(N^2)(O(1))不稳定是冒泡排序O(N^2)(O(1))稳定是插入排序O(N^2)(O(1))稳定是归并排序O(N\log N)(O(N))稳定是快速排序O(N\log N)O(log N)不稳定是堆排序O(N\log N)O(1)不稳定是计数排序(O(N + M))O(M))稳定否基数排序O(N)稳定否桶排序平均O(N) / 最坏O(N^2)

2401_87069538的博客 609
上一篇: P10721 [GESP202406 六级] 计算得分
下一篇: P11247 [GESP202409 六级] 算法学习
谢天谢地AC了 | 信奥教练
博客等级 码龄1年 53粉丝 177原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值