[GESP202406 六级] 二叉树

题目描述

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

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

输入格式

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

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

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

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

接下来 q q q 行每行⼀个正整数 a i a_i ai 1 ≤ a i ≤ n 1\le a_i\le n 1ain),表示第 i i i 次操作选择的节点编号。

输出格式

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

输入输出样例 #1

输入 #1

6
3 1 1 3 4
100101
3
1
3
2

输出 #1

010000

说明/提示

样例解释

第一次操作后,节点颜色为: 011010 \texttt{011010} 011010

第二次操作后,节点颜色为: 000000 \texttt{000000} 000000

第三次操作后,节点颜色为: 010000 \texttt{010000} 010000

数据范围

子任务编号得分 n n n q q q特殊条件
1 1 1 20 20 20 ≤ 1 0 5 \le 10^5 105 ≤ 1 0 5 \le 10^5 105对于所有 i ≥ 2 i\ge 2 i2,节点 i i i 的父亲节点编号为 i − 1 i-1 i1
2 2 2 40 40 40 ≤ 1000 \le 1000 1000 ≤ 1000 \le 1000 1000
3 3 3 40 40 40 ≤ 1 0 5 \le 10^5 105 ≤ 1 0 5 \le 10^5 105

对于全部数据,保证有 n , q ≤ 1 0 5 n,q\le 10^5 n,q105

提交链接

二叉树

思路分析

暴力搜索(40分)

读取输入

cin >> n; // 读取二叉树的结点个数
for(int i = 2; i <= n; i++) {
    cin >> f[i];  // 读取每个节点的父节点编号
}
cin >> color;
color = ' ' + color;  // 让 color[1] 对应编号 1(为了方便索引)
cin >> q;
  • n n n 是二叉树的节点数,编号从 1 1 1 n n n
  • f [ i ] f[i] f[i] 记录 编号为 i i i 的节点的父节点(即 f [ i ] f[i] f[i] i i i 的直接父节点)。
  • c o l o r color color 是一个 01 01 01 字符串,表示初始颜色。
  • q q q 是操作次数。

记录操作次数

while(q--) {  
    cin >> x;  // 选择节点 x 作为操作的根
    num[x] = (num[x] + 1) % 2;  // 记录节点 x 被操作的奇偶性
}

n u m [ x ] num[x] num[x] 记录以 x x x 为根的子树被操作的次数的奇偶性:

  • 如果 n u m [ x ] num[x] num[x] 是偶数,说明 x x x 的子树 颜色未变。
  • 如果 n u m [ x ] num[x] num[x] 是奇数,说明 x x x 的子树 颜色被翻转了一次。

遍历所有节点并计算最终颜色

for(int i = 1; i <= n; i++) {
    sum = 0;
    dfs(i);  // 计算 i 节点受到多少次翻转影响
    if(sum & 1) {  // 如果翻转次数是奇数
        if(color[i] == '1') color[i] = '0';
        else color[i] = '1';
    }
}

核心思想:

  • 遍历所有 i i i,计算 i i i 这个节点从 它自身到根节点 经过的 翻转次数 s u m sum sum
  • 如果 s u m sum sum 是奇数,就翻转 i i i 这个节点的颜色。

计算 i i i 受到的翻转次数

void dfs(int x) {
    if(num[x]) sum++;  // 如果 x 这个节点被操作了,就增加翻转次数
    if(f[x] == 0) return;  // 递归终止:已经到达根节点
    dfs(f[x]);  // 继续递归到父节点
}

递归 d f s ( x ) dfs(x) dfs(x)

  • 如果 x x x 本身是翻转点( n u m [ x ] = = 1 num[x] == 1 num[x]==1), s u m + + sum++ sum++
  • 继续向 f [ x ] f[x] f[x](父节点)递归,直到到达根节点。
  • 这样 s u m sum sum 记录的是 从 x x x 到根节点的所有翻转次数。

输出最终颜色

for(int i = 1; i <= n; i++)
    cout << color[i];

直接输出所有节点最终的颜色。

存在的问题

d f s ( i ) dfs(i) dfs(i) 重复计算了很多次。

  • 每个 i i i 都要从自己走到根,而 有些 i i i 的路径是重复的,造成大量冗余计算。
  • 树高最多是 O ( n ) O(n) O(n),最坏情况下变成 O ( n 2 ) O(n²) O(n2)。如果树是链状结构,则 d f s ( i ) dfs(i) dfs(i) 的调用深度最坏是 n n n,遍历所有 n n n 个节点就会导致 O ( n 2 ) O(n²) O(n2) 复杂度。

参考代码:

#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 9;

int n , q , f[MAX_N] , x , num[MAX_N] , sum;
string color;

void dfs(int x)
{
    if(num[x])
        sum++;
    if(f[x] == 0)
        return;
    dfs(f[x]);
    
}

int main()
{
    cin >> n; //二叉树的结点个数
    for(int i = 2; i <= n; i++)
        cin >> f[i];  //f[i]:结点i的父亲结点的编号
    
    cin >> color;
    color = ' ' + color;  //color[i]:编号为i的结点的颜色,color[i]=1为黑色 color[i]=0为白色

    cin >> q;

    while(q--)  //q次询问
    {
        cin >> x;  //选择编号为x的结点
        num[x] = (num[x] + 1) % 2;  //记录根结点为x的子树操作的次数
    }

    for(int i = 1; i <= n; i++)
    {
        sum = 0;
        dfs(i);
        if(sum & 1)
        {
            if(color[i] == '1')
                color[i] = '0';
            else
                color[i] = '1';
        }
    }
    for(int i = 1; i <= n; i++)
        cout << color[i];
    return 0;
}

搜索优化(100分)

改进点:

  1. 改进翻转标记方式

    • 仍然使用 n u m [ x ] num[x] num[x] 记录操作次数,但不再逐个节点 D F S ( i ) DFS(i) DFS(i) 计算 s u m sum sum
    • 采用 子树 DFS 传播翻转状态,避免重复计算 s u m sum sum
  2. 高效的 DFS 处理方式

    • 构建子树关系:G[f[i]].push_back(i) 记录子节点,而不是用 f[x] 记录父节点。
    • 从根遍历一次 DFS 传递翻转状态:
      • c h e c k check check 变量标记当前节点是否应被翻转。
      • 遍历整个子树,每个节点仅访问一次,避免重复计算。
  3. 时间复杂度分析

    • 树的遍历是 O ( n ) O(n) O(n)
    • 建树 O ( n ) O(n) O(n)
    • 一次 DFS 处理整个树 O ( n ) O(n) O(n)
    • 总时间复杂度 O ( n ) O(n) O(n)

参考代码:

#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 9;

int n , q , f[MAX_N] , x , num[MAX_N] , sum;
string color;
vector<int>G[MAX_N];

void dfs(int x)
{
    if(num[x])
        sum++;
    if(f[x] == 0)
        return;
    dfs(f[x]);
}

void dfs(int x , bool check)
{
    
    if(check && num[x])   //check为父结点带来的影响  num[x]为本身是否需要操作
        check = false;
    else if(!check && num[x] || check && !num[x])
        check = true;
    
    if(check)
    {
        if(color[x] == '1')
            color[x] = '0';
        else
            color[x] = '1';
    }

    for(auto it : G[x])
        dfs(it , check);
}

int main()
{
    cin >> n; //二叉树的结点个数
    for(int i = 2; i <= n; i++)
    {
        cin >> f[i];  //f[i]:结点i的父亲结点的编号
        G[f[i]].push_back(i);  //儿子存储法
    }
    
    cin >> color;
    color = ' ' + color;  //color[i]:编号为i的结点的颜色,color[i]=1为黑色 color[i]=0为白色

    cin >> q;

    while(q--)  //q次询问
    {
        cin >> x;  //选择编号为x的结点
        num[x] = (num[x] + 1) % 2;  //记录根结点为x的子树操作的次数
    }

    dfs(1 , false);

    for(int i = 1; i <= n; i++)
        cout << color[i];
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/973655.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数学】数论干货(疑似密码学基础)

文章目录 前言一. 整除、算术基本定理、同余、同余类、剩余系的基本定义1.整除2.算数基本定理3.同余4.同余类&#xff08;也叫剩余类&#xff09;5.剩余系 二. 费马小定理的内容及其证明1.费马小定理基本内容2.费马小定理的证明&#xff08;interesting 版&#xff09; 三. 欧拉…

[实现Rpc] 消息抽象层的具体实现

目录 具象层 _ 消息抽象的实现 信息的抽象类 实现 JsonMessage JsonRequest & JsonResponse 消息-不同消息分装实现 实现 Request RpcRequest TopicRequest ServiceRequest Response RpcResponse TopicResponse ServiceResponse 实现 生产工厂 本篇文章继 …

《A++ 敏捷开发》- 16 评审与结对编程

客户&#xff1a;我们的客户以银行为主&#xff0c;他们很注重质量&#xff0c;所以一直很注重评审。他们对需求评审、代码走查等也很赞同&#xff0c;也能找到缺陷&#xff0c;对提升质量有作用。但他们最困惑的是通过设计评审很难发现缺陷。 我&#xff1a;你听说过敏捷的结对…

PHP房屋出租出售高效预约系统小程序源码

&#x1f3e0; 房屋出租出售高效预约系统 —— 您的智能找房新选择 &#x1f4a1; 这是一款集智慧与匠心于一体的房屋出租出售预约系统&#xff0c;它巧妙地融合了ThinkPHP与Uniapp两大先进框架&#xff0c;精心打造而成。无论是小程序、H5网页&#xff0c;还是APP端&#xff…

给老系统做个安全检查——Burp SqlMap扫描注入漏洞

背景 在AI技术突飞猛进的今天&#xff0c;类似Cursor之类的工具已经能写出堪比大部分程序员水平的代码了。然而&#xff0c;在我们的代码世界里&#xff0c;仍然有不少"老骥伏枥"的系统在兢兢业业地发光发热。这些祖传系统的代码可能早已过时&#xff0c;架构可能岌…

Repeated Sequence

记suma[1]a[2]a[3]...a[n]。 该序列以a[1]&#xff0c;a[2]&#xff0c;a[3]....a[n]为循环节&#xff0c;明显的&#xff0c;问题可转化为:s%sum是否为该序列的某个连续子序列和。 断环为链。将a复制一份。 枚举a[i]为左端点的所有区间的和。再查找s是否存在。二分O&#x…

【DeepSeek】Mac m1电脑部署DeepSeek

一、电脑配置 个人电脑配置 二、安装ollama 简介&#xff1a;Ollama 是一个强大的开源框架&#xff0c;是一个为本地运行大型语言模型而设计的工具&#xff0c;它帮助用户快速在本地运行大模型&#xff0c;通过简单的安装指令&#xff0c;可以让用户执行一条命令就在本地运…

dockerfile 使用环境变量

ARG&#xff1a; Defining build-time variables ARG指令允许您定义在构建阶段可以访问但在构建映像之后不可用的变量。例如&#xff0c;我们将使用这个Dockerfile来构建一个映像&#xff0c;我们在构建过程中使用ARG指令指定的变量。 FROM ubuntu:latest ARG THEARG"fo…

基于WebGIS技术的校园地图导航系统架构与核心功能设计

本文专为IT技术人员、地理信息系统&#xff08;GIS&#xff09;开发者、智慧校园解决方案架构师及相关领域的专业人士撰写。本文提出了一套基于WebGIS技术的校园地图导航系统构建与优化方案&#xff0c;旨在为用户提供高效、智能、个性化的导航体验。如需获取校园地图导航系统技…

idea连接gitee(使用idea远程兼容gitee)

文章目录 先登录你的gitee拿到你的邮箱找到idea的设置选择密码方式登录填写你的邮箱和密码登录成功 先登录你的gitee拿到你的邮箱 具体位置在gitee–>设置–>邮箱管理 找到idea的设置 选择密码方式登录 填写你的邮箱和密码 登录成功

【从0做项目】Java音缘心动(3)———加密算法 MD5 BCrypt

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 零&#xff1a;项目结果展示 一&#xff1a;音乐播放器Web网页介绍 二&#xff1a;加密算法介绍 1&…

新数据结构(12)——代理

什么是代理 在进行操作时有时不希望用户直接接触到目标&#xff0c;这时需要使用代理让用户间接接触到目标 给目标对象提供一个代理对象&#xff0c;并且由代理对象控制着对目标对象的引用 图解&#xff1a; 代理的目的 控制访问&#xff1a;通过代理对象的方式间接的访问目…

基于大语言模型的推荐系统(1)

推荐系统&#xff08;recommendation system&#xff09;非常重要。事实上&#xff0c;搜索引擎&#xff0c;电子商务&#xff0c;视频&#xff0c;音乐平台&#xff0c;社交网络等等&#xff0c;几乎所有互联网应用的核心就是向用户推荐内容&#xff0c;商品&#xff0c;电影&…

学习threejs,使用MeshBasicMaterial基本网格材质

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.MeshBasicMaterial 二…

Selenium实战案例2:东方财富网股吧评论爬取

上一篇文章&#xff0c;我们使用Selenium完成了网页内文件的自动下载,本文我们将使用Selenium来爬取东方财富网股吧内笔记的评论数据。 网页内容分析 网页内容的分析是web自动化中的关键一步。通过分析网页结构&#xff0c;我们可以确定需要抓取的数据位置以及操作元素的方式。…

零基础学python--------第三节:Python的流程控制语法

Python&#xff0c;浮点数 11.345(单&#xff1a;4个字节&#xff0c; 双&#xff1a;8个字节) 。 十进制的数字25 ---> 11001 讲一个小数转化为二进制&#xff1a; 不断的乘以2 。取整数部分。 十进制的0.625 ----> 二进制&#xff1a; 0&#xff0c; 101 。 0.3 ---…

MKS SERVO42E57E 闭环步进电机_系列10 STM32_脉冲和串口例程

文章目录 第1部分 产品介绍第2部分 相关资料下载2.1 MKS E系列闭环步进驱动资料2.2 源代码下载2.3 上位机下载 第3部分 脉冲控制电机运行示例第4部分 读取参数示例4.1 读取电机实时位置4.2 读取电机实时转速4.3 读取电机输入脉冲数4.4 读取电机位置误差4.5 读取电机IO端口状态 …

小米路由器 AX3000T 降级后无法正常使用,解决办法

问题描述 买了个 AX3000T 路由器&#xff0c;想安装 OpenWRT 或者 安装 Clash 使用&#xff0c;看教程说是需要降级到 v1.0.47 版本。 结果刷机之后路由器无法打开了&#xff0c;一直黄灯亮&#xff0c;中间灭一下&#xff0c;又是黄灯长亮&#xff0c;没有 WIFI 没有连接。以…

强化学习-GAE方法

2016-ICLR-HIGH-DIMENSIONAL CONTINUOUS CONTROL USING GENERALIZED ADVANTAGE ESTIMATION 解决问题 强化学习的目标为最大化策略的预期总回报&#xff0c;其中一个主要困难为 行为对reward的影响存在一个长时间的延迟&#xff08;credit assignment problem&#xff09;。价…

写大论文的word版本格式整理,实现自动生成目录、参考文献序号、公式序号、图表序号

前情提要&#xff1a;最近开始写大论文&#xff0c;发现由于内容很多导致用老方法一个一个改的话超级麻烦&#xff0c;需要批量自动化处理&#xff0c;尤其是序号&#xff0c;在不断有增添删减的情况时序号手动调整很慢也容易出错&#xff0c;所以搞一个格式总结&#xff0c;记…