蓝桥杯 2023 省A 颜色平衡树

news2024/11/18 7:29:26

树上启发式合并是一个巧妙的方法。
 

dsu on tree,可以称为树上启发式合并,是一种巧妙的暴力。用一个全局数组存储结果,对于每棵子树,有以下操作:

先遍历轻儿子,处理完轻儿子后将数组清零(要再遍历一次来清零)
遍历重儿子,遍历完不用清零,再遍历,将轻儿子合并到重儿子上去,其合并结果存储于全局数组
用此时的全局数组来计算父亲
重儿子: 对于一个非叶节点u ,设v 是u 的儿子,且以v 为根的子树包含的节点比以u 的其他儿子为根的子树包含的节点都多,则称v 为u 的重儿子

轻儿子: 对于一个非叶节点u ,在u 的各个儿子中,除了重儿子,都是轻儿子

这题还有个关键就是如何判断是否所有存在的颜色个数相同
有个好思路就是,设立全局变量min和max,表示的是子树u的存在的的颜色的最多数量和最小数量,若min==max,则就是满足条件的子树。


 

#include <iostream>
#include <bits/stdc++.h> // 包含常用的标准库头文件
using namespace std;

int n; // 存储节点数量

// 结构体定义边
struct edge
{
    int y, next; // 存储节点编号和下一条边的位置
} e[400002]; // 全局数组,存储边信息

int first[200001]; // 存储每个节点的第一条边的位置
// 第一个参数为节点编号,第二个参数为节点的颜色编号
int col[200001];
// 存储每个节点的子树大小和重儿子
int size[200001], mson[200001];
// 存储每个颜色对应的节点数量,以及该数量对应的颜色数量
int t[2][200010], mi, ma;
int ans; // 存储结果

// 添加边的函数
void add_edge(int x, int y)
{
    static int len = 0; // 静态变量,用于记录边的数量
    e[++len] = {y, first[x]}; // 将边的信息存入数组中
    first[x] = len; // 更新节点的第一条边的位置为当前边的位置
}

// 深度优先搜索,用于计算每个节点的子树大小和重儿子
void dfs0(int x)
{
    size[x] = 1; // 初始化当前节点的子树大小为1
    // 遍历当前节点的每一条边
    for (int i = first[x]; i != 0; i = e[i].next)
    {
        int y = e[i].y; // 获取当前边连接的节点编号
        dfs0(y); // 递归调用,计算子树的大小
        // 更新当前节点的重儿子
        if (size[y] > size[mson[x]])
            mson[x] = y;
        size[x] += size[y]; // 更新当前节点的子树大小
    }
}

// 添加节点颜色数量信息到数组t中
void add(int x)
{
    t[1][t[0][x]]--; // 将原来颜色数量对应的颜色数量减1
    t[0][x]++; // 将当前颜色数量加1
    t[1][t[0][x]]++; // 将新的颜色数量对应的颜色数量加1
    // 更新颜色数量的最小值和最大值
    if (t[0][x] < mi)
        mi = t[0][x];
    if (t[0][x] > ma)
        ma = t[0][x];
    // 如果颜色数量为0,则颜色数量最小值加1
    if (!t[1][mi])
        mi++;
}

// 删除节点颜色数量信息从数组t中
void del(int x)
{
    t[1][t[0][x]]--; // 将原来颜色数量对应的颜色数量减1
    t[0][x]--; // 将当前颜色数量减1
    t[1][t[0][x]]++; // 将新的颜色数量对应的颜色数量加1
    // 更新颜色数量的最小值
    if (t[0][x] && t[0][x] < mi)
        mi = t[0][x];
    // 如果颜色数量为0,则颜色数量最大值减1
    if (!t[1][ma])
        ma--;
}

// 遍历以x为根节点的子树,根据type类型进行颜色数量的操作
void dfs1(int x, int type)
{
    if (type == 0)
        del(col[x]); // 删除节点颜色数量信息
    else
        add(col[x]); // 添加节点颜色数量信息
    // 遍历当前节点的每一个子节点
    for (int i = first[x]; i; i = e[i].next)
    {
        int y = e[i].y; // 获取当前边连接的节点编号
        dfs1(y, type); // 递归调用,处理子节点的信息
    }
}

// 遍历以x为根节点的子树,统计颜色数量相等的子树数量
void dfs2(int x)
{
    // 遍历当前节点的每一个子节点
    for (int i = first[x]; i; i = e[i].next)
    {
        int y = e[i].y; // 获取当前边连接的节点编号
        // 如果当前节点是重儿子,则跳过
        if (y == mson[x])
            continue;
        dfs2(y); // 递归调用,处理非重儿子的子树
        dfs1(y, 0); // 处理非重儿子的节点颜色数量信息
    }
    // 如果存在重儿子,则处理重儿子的子树
    if (mson[x])
        dfs2(mson[x]);
    // 遍历当前节点的每一个子节点
    for (int i = first[x]; i; i = e[i].next)
    {
        int y = e[i].y; // 获取当前边连接的节点编号
        // 如果当前节点是重儿子,则跳过
        if (y == mson[x])
            continue;
        dfs1(y, 1); // 处理非重儿子的节点颜色数量信息
    }
    add(col[x]); // 添加当前节点的颜色数量信息
    // 如果颜色数量最小值等于颜色数量最大值,说明当前子树中的颜色数量相等
    if (mi == ma)
        ans++;
}

int main()
{
    cin >> n; // 输入节点数量
    int y; // 存储父节点编号
    for (int i = 1; i <= n; i++)
    {
        cin >> col[i] >> y; // 输入节点颜色和父节点编号
        add_edge(y, i); // 添加边信息
    }
    dfs0(1); // 计算每个节点的子树大小和重儿子
    mi = 1; // 初始化颜色数量的最小值为1
    dfs2(1); // 遍历树的根节点,并统计颜色数量相等的子树数量
    cout << ans; // 输出结果
    return 0;
}

进一步注释:
 

len配合first数组,可以记录边的序号。

edge 结构体定义了树的边的信息,其中 ynext 分别代表了以下含义:

  • y:表示当前边所连接的节点的编号。在树的边结构中,每条边连接两个节点,y 就是其中一个节点的编号,表示了这条边连接到了哪个节点。

  • next:表示当前节点 x 的下一条邻接边在边数组中的位置。因为这是一个邻接表的表示方式,所以 next 记录了节点 x 的下一条邻接边在边数组中的位置,以便能够快速地遍历节点 x 的所有邻接边。

t[2][200001]:
       第一行 (t[0][...]) 用于记录每种颜色出现的次数。
       第二行 (t[1][...]) 用于记录不同出现次数的颜色数目。

具体地,t[0][x] 表示颜色 x 出现的次数,而 t[1][y] 表示出现 y 次的不同颜色的数目。通过这个数组,可以实现对每种颜色的统计。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java中的SSM框架实现快餐店线上点餐系统项目【项目源码+论文说明】计算机毕业设计

基于Java中的SSM框架实现快餐店线上点餐系统演示 摘要 随着计算机互联网的高速发展。餐饮业的发展也加入了电子商务团队。各种网上点餐系统纷纷涌现&#xff0c;不仅增加了商户的销售量和营业额&#xff0c;而且为买家提供了极大的方便&#xff0c;足不出户&#xff0c;就能订…

【机器学习300问】50、什么是基于用户的协同过滤算法?

一、 基于用户的协同过滤算法直观感受 假设你在一家大型书店&#xff0c;店主不仅知道你过去的购买记录&#xff0c;还了解其他所有顾客的购买行为。当你要寻找下一本喜欢的书籍时&#xff0c;店主不是根据书籍本身的属性来推荐&#xff08;比如作者、类型&#xff09;&#xf…

RPC 快速入门

一、What 1&#xff09;小故事 张三和李四都在同一个家公司负责商品交易的模块&#xff0c;两个人平时开发甚是紧密。 &#x1f64b;&#x1f3fb;‍♂️ 张三&#xff1a;“李四&#xff0c;我这边一个商品下单了&#xff0c;但是付款数额不对&#xff0c;你帮我查下支付有没…

【应用笔记】LAT1305+使用STM32+TT类型IO的注意事项

1. 概述 在 STM32 系列 MCU 中&#xff0c; 除了一些特殊管脚外&#xff0c;绝大多数管脚都可以分类为 FT (兼容5V 信号)或 TT&#xff08;兼容 3V3 信号&#xff09;类型的 IO&#xff0c;由于 MCU 内部设计的不同&#xff0c; TT IO 相比 5V IO 有更多的限制&#xff0c;下面…

【机器学习】包裹式特征选择之序列前向选择法

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

Jenkins中使用Generic Webhook Trigger插件实现持续集成

项目环境 宝塔Linux面板DockerJenkinsgitee 目的 实现每次push推送dev分支到gitee上&#xff0c;Jenkins自动构建项目&#xff1b;push其它分支时&#xff0c;不运行。 实现方法 1.在Jenkins上安装Generic Webhook Trigger插件 在“系统设置–插件管理–可选插件”界面搜…

1-Flume中agent的source

Flume&#xff08;1.11.0版本&#xff09; 简介 概述 Flume本身是由Cloudera公司开发的后来贡献给了Apache的一套针对日志数据进行收集(collecting)、汇聚(aggregating)和传输(moving)的机制 Flume本身提供了简单且灵活的结构来完成日志数据的传输 Flume有两大版本&#x…

有道翻译实现接口加密解密

文章目录 目标简单逆向分析源码深度逆向分析参考文献目标 实现对网易有道 sign 等参数的加密 及 返回的密文数据解密实现 简单逆向分析 首先在右上角提前登录好账号信息。 输入中文:你好 要求翻译成:英文 全局搜索:你好 或 hello,结果没有发现什么。 切换 Fetch/XHR …

JAVA毕业设计131—基于Java+Springboot+Vue的餐厅点餐系统(源代码+数据库+4000字文档)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的餐厅点餐系统(源代码数据库4000字文档)131 一、系统介绍 本项目前后端分离&#xff0c;分为管理员、用户两种角色 1、用户&#xff1a; 注册、登录、点餐…

移动0【双指针】

移动零 cur每次走一步&#xff0c;dest走不走取决于cur有没有找到非0值&#xff0c;一旦找打非0值&#xff0c;交换。不是非0值&#xff0c;dest不动。》【非零&#xff0c;dest】【dest&#xff0c;0】 class Solution { public:void moveZeroes(vector<int>& num…

电脑不能读取移动硬盘,但是可以读取U盘解决方法

找到此电脑 右键设备管理器&#xff0c;找到其中的通用串行总线控制器。 注意&#xff0c;凡是插入到电脑当中不能读取的U盘或者移动硬盘&#xff0c;都会在通用串行总线控制器当中显示为USB大容量存储设备 鼠标选中“USB大容量存储设备”&#xff0c;右键卸载它。此时&#x…

[项目前置]websocket协议

websocket协议介绍 WebSocket 协议是一种在单个 TCP 连接上进行全双工通讯的协议。 WebSocket 使得客户端和服务器之间的数据交换变得更简单&#xff0c;允许服务器主动向客户端推送数据。它在 2011 年成为国际标准&#xff0c;现在被所有现代浏览器支持。WebSocket 设计用于…

【蓝桥杯选拔赛真题72】python找路线 第十四届青少年组蓝桥杯python选拔赛真题 算法思维真题解析

目录 python找路线 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python找路线 第十四届蓝桥杯青少年组python比赛选拔赛真题 一、题目要求 …

mysql基础2多表查询

多表查询 多表关系: 一对多 案例: 部门 与 员工的关系 关系: 一个部门对应多个员工&#xff0c;一个员工对应一个部门 实现: 在多的一方建立外键&#xff0c;指向一的一方的主键 多对多 案例: 学生 与 课程的关系 关系: 一个学生可以选修多门课程&#xff0c;一门课程也可以…

鸿蒙实战开发:【7日天气预报】

先来看一下效果 本项目界面搭建基于ArkUI中TS扩展的声明式开发范式&#xff0c; 数据接口是[和风&#xff08;天气预报&#xff09;]&#xff0c; 使用ArkUI自带的网络请求调用接口。 我想要实现的一个功能是&#xff0c;查询当前城市的实时天气&#xff0c; 目前已实现的功…

阿里云服务器价格表2024,最新报价2核2G/2核4G/4核8G/8核16G/16核32G

2024年腾讯云服务器优惠价格表&#xff0c;一张表整理阿里云服务器最新报价&#xff0c;阿里云服务器网整理云服务器ECS和轻量应用服务器详细CPU内存、公网带宽和系统盘详细配置报价单&#xff0c;大家也可以直接移步到阿里云CLUB中心查看 aliyun.club 当前最新的云服务器优惠券…

【嵌入式学习】Qtday03.24

一、思维导图 二、练习 QMovie *mv new QMovie(":/Logo/giphy (2).gif");ui->label_5->setMovie(mv);ui->label_5->setScaledContents(true);mv->start();this->setWindowIcon(QIcon(":/Logo/bdf48b5198c8417da0e4fef6b72c5657.png"));/…

mysql 存储引擎 基本介绍

目录 一 存储引擎概念介绍 &#xff08;一&#xff09;存储引擎概念 &#xff08;二&#xff09;MySQL常用的存储引擎 &#xff08;三&#xff09;存储引擎运作方式 二 MyISAM 存储引擎介绍 &#xff08;一&#xff09; MyISAM 存储引擎特点 1&#xff0c;不支持…

WorkPlus AI助理,为企业提供智能化客户服务,助力企业发展与竞争力

在当今竞争激烈的商业环境中&#xff0c;提供优质高效的客户服务是企业取得成功的关键。而AI智能客服的崛起&#xff0c;以其卓越的性能和功能&#xff0c;助力企业提升客户服务体验。WorkPlus AI助理作为一款领先的解决方案&#xff0c;能够实现智能化客户服务&#xff0c;满足…

SVN的branch分支合并完要不要删除

在 SVN 中&#xff0c;当一个分支&#xff08;branch&#xff09;的工作已经完成并成功合并回主干&#xff08;trunk&#xff09;后&#xff0c;通常不需要立即删除该分支。保留分支可以有一些好处&#xff0c;例如&#xff1a; 历史记录和追溯&#xff1a;保留分支可以帮助团…