洛谷题单指南-图论之树-P5588 小猪佩奇爬树

news/2025/3/14 16:29:57/文章来源:https://www.cnblogs.com/jcwy/p/18771762

原题链接:https://www.luogu.com.cn/problem/P5588

题意解读:树中每个节点有一种颜色,计算每种颜色所有节点能用一条路径穿过的路径数。

解题思路:

直接枚举所有路径显然不可取,需要分情况来讨论,用乘法原理来解决。

首先,要通过dfs预处理出一些信息:siz[i]:节点i子树大小,depth[i]:i的深度,

再将所有颜色对应的节点按深度大到小保存,vector<int> colors[N],colors[i]表示颜色i的所有节点。

然后,枚举每一种颜色,对每一种颜色的所有节点进行处理,一共分4种情况:

1、节点数为0

对于没有的颜色, 题目已经明确所有点对都满足,点对总数量是n * (n - 1) / 2

2、节点数为1

如图中红色节点只有2号,那么能经过2号节点的路径数就是两个三线框中节点数对所有外部其他点数乘积之和,再加上从2出发到所有点的路径数,最后再除以2,一共是(siz[5] * (n - siz[5])) + siz[6] * (n - siz[6]) + (n - siz[2]) * siz[2] + n - 1) / 2

3、节点数>=2,且所有节点都在一条链上

在一颗树中,所有节点都在一条链上只可能是两种情况:

第一种:所有节点存在祖先关系。

如图,2/6分别是深度最小和最大的两个节点,他们在一条链6-2上,且存在祖先关系(当然,2和6之间还可以有其他红色节点),这样能经过这段路径的数量就是两个虚线框中节点数量的乘积,即siz[6] * (n - siz[2在链上的子节点])

那么,问题就在于如何判断所有节点存在祖先关系?

可以借助于LCA,依次取每一个节点与深度最大的节点计算LCA,如果LCA得到的结果都是深度较小的节点,说明所有节点在存在祖先关系的一条链上。

第二种:所有节点分两个子集,每个子集的节点存在祖先关系。

如图,2/6存在祖先关系,4与2/6不存在祖先关系,他们都在一条链6-2-1-4上,能经过这段路径的数量就是两个虚线框中节点数量的乘积,

即siz[6] * siz[4]

那么,如何判断节点存在两组祖先关系?

可以从深度最大的节点开始,找到两个不存在祖先关系的深度最大的节点,设这两个节点的LCA为o,然后其余节点分别和这两个节点进行LCA,如果LCA的结果都是等于深度较小的节点,并且这个节点的深度大于等于o的深度,说明这些节点是在两组祖先关系的链中且最终可以串起来。

4、节点数>=2,所有节点无法连成一条链

在上面判断节点的关系时,如果发现有节点和深度最大两个没有祖先关系的节点都没有祖先关系,或者有祖先关系但是lca的深度小于o的深度,说明这些节点无法串成一条链,那么结果就是0。

100分代码:

#include <bits/stdc++.h>
using namespace std;const int N = 1000005;vector<int> g[N];
vector<int> colors[N]; //颜色对应的节点,按深度大到小排序
int c[N]; //节点颜色
int depth[N]; //节点深度
int siz[N]; //子树大小
int fa[N][20]; //倍增数组,fa[u][i]表示u的第2^i个祖先
int n;bool cmp(int x, int y)
{return depth[x] > depth[y];
}void dfs(int u, int p)
{depth[u] = depth[p] + 1; //lca的根节点深度一定要是1siz[u] = 1;fa[u][0] = p;for(int i = 1; i <= 19; i++){fa[u][i] = fa[fa[u][i-1]][i-1];}for(int v : g[u]){if(v == p) continue;dfs(v, u);siz[u] += siz[v];}
}int lca(int u, int v)
{if(depth[u] < depth[v]) swap(u, v);for(int i = 19; i >= 0; i--){if(depth[fa[u][i]] >= depth[v]){u = fa[u][i];}}if(u == v) return u;for(int i = 19; i >= 0; i--){if(fa[u][i] != fa[v][i]){u = fa[u][i];v = fa[v][i];}}return fa[u][0];
}int main()
{cin >> n;for(int i = 1; i <= n; i++){cin >> c[i];colors[c[i]].push_back(i);}for(int i = 1; i < n; i++){int u, v;cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs(1, 0);for(int i = 1; i <= n; i++){sort(colors[i].begin(), colors[i].end(), cmp);}for(int i = 1; i <= n; i++){long long ans = 0;if(colors[i].size() == 0) ans += 1ll * n * (n - 1) / 2;else if(colors[i].size() == 1) {int s1 = colors[i][0]; //深度最大的节点for(auto v : g[s1]) {if(v == fa[s1][0]) continue;ans += 1ll * siz[v] * (n - siz[v]); //所有子树的贡献}ans += 1ll * (n - siz[s1]) * siz[s1] + n - 1; //父节点所在子树的贡献以及从s1出发的所有贡献ans /= 2;}else{int s1 = colors[i][0]; //深度最大的节点int s2 = 0; //深度次大且与s1没有祖先关系的节点for(int j = 1; j < colors[i].size(); j++){int u = colors[i][j];if(lca(s1, u) != u) // u不是s1的祖先{s2 = u;break;}}if(s2 == 0) // 没有找到s2,说明所有节点都在一条链上{int s3 = s1; //链上深度最小的节点的子节点for(int j = 19; j >= 0; j--){if(fa[s3][j] != 0 && depth[fa[s3][j]] > depth[colors[i].back()])s3 = fa[s3][j];}ans += 1ll * siz[s1] * (n - siz[s3]);}else{int l = lca(s1, s2);bool ok = true;for(int u : colors[i]){// 检查是否所有颜色节点都在s1或s2的祖先中,且不在lca的上方if(depth[u] < depth[l] || (lca(u, s1) != u && lca(u, s2) != u)){ok = false;break;}}if(ok) ans += 1ll * siz[s1] * siz[s2];}}cout << ans << endl;}
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双非一本,小公司打杂,跳槽进了大厂!

大家好,我是R哥。 好久没有分享面试辅导的成功案例了,图片打码、过程梳理、文章编写,着实难写啊,太费时间了。 今天和大家分享一个普通本科、不知名小公司程序员,成功逆袭互联网大厂的真实案例。 如果你觉得自己学历一般,背景普通,没有 “985/211” 学历加持,也没有中大…

No.65 Vue---Axios 网络请求、Axios 网络的请求封装、网络请求跨域解决方案

一、Axios 网络请求Axios 是一个基于 promise 的网络请求库。1.1 安装ctrl + c :停止服务。 安装:npm install -save axios 安装完启动原来的服务:npm run serve 1.2 引入局部引用:import axios from axios; //局部引用 全局引用: 1.3 get请求方式//get請求方式axios({met…

我的博客开启啦

由于微信访问限制,请长按识别下方二维码跳转下载

FastAPI复杂查询终极指南:告别if-else的现代化过滤架构

title: FastAPI复杂查询终极指南:告别if-else的现代化过滤架构 date: 2025/3/14 updated: 2025/3/14 author: cmdragon excerpt: 本文系统讲解FastAPI中复杂查询条件的构建方法,涵盖参数验证、动态过滤、安全防护等18个核心技术点。通过引入策略模式、声明式编程等技术,彻…

基于Ollama本地部署DeepSeek-r1:7b大语言模型

1、概述随着人工智能技术的飞速发展,越来越多的开发者和企业开始关注大语言模型(LLM)。这些模型以其强大的自然语言处理能力,在文本生成、问答、翻译、分类等多种任务中表现出色。然而,在实际使用中,许多人会遇到如何快速且高效地部署这些模型的问题。本文将介绍如何通过…

web116笔记(misc+lfi)

访问题目是一个视频,源码也没有什么有用信息 提示:misc+lfi 下载视频,使用 010editor 打开,发现存在 png 图片的数据,搜索另存为 过滤了蛮多的,不过没有过滤flag ,也没有过滤 filter 尝试构造语句?file=php://filter/resource=flag.php (直接读取) 如果没有设置 fil…

具身智能

Topic I: 3D VIsion Topic II: Robotics Topic IV: Reinforcement learning Linear Algebra Vector Space 向量空间Linear Combination 线性组合\(w=a_1v_1+a_2v_2+...+a_nv_n=\sum_i a_iv_i\)Span of Vectors\(v_i \in V_m\), \(w \in V_m\)Infinite-Ddimensional Vector Spac…

python的jieba

jieba 是一个广泛使用的 Python 中文分词库,主要用于将中文文本切分成独立的词语。 https://github.com/fxsjy/jieba 安装pip install jieba使用 (1)分词import jieba # 分词 text = "我爱自然语言处理" words = jieba.cut(text, cut_all=False) # 精确模式 prin…

3. 创建一个菜单组件-DeepSeek辅助编程

在deepseek中输入: 创建一个vue组件 组件实现菜单的功能 需要让调用该组件是可以自定义一些属性:mode:horizontal横向显示/vertical纵向显示,background-color,text-color,active-text-color,model:通过该model绑定菜单/model为MenuItem的数组 MenuItem由这些参数构成:inde…

微信支付相关配置

公众号相关配置 地址:https://mp.weixin.qq.com/一、获取用户openid相关配置 二、获取开发者ID(AppID)/开发者密码(AppSecret) 微信支付相关配置 地址:https://pay.weixin.qq.com/需要先申请开通支付产品微信支付相关参数获取: 一:获取商户号(商户号mach_id)三、获取证书…

华为开发者空间:基于DeepSeek+Cherry Studio构建模拟面试助手

通过实际操作,让开发者熟悉如何通过云主机部署DeepSeek,以及如何将DeepSeek与Cherry Studio结合起来帮助我们解决一些实际的问题。本文分享自华为云社区《华为开发者空间:基于DeepSeek+Cherry Studio构建模拟面试助手》,作者:开发者空间小蜜蜂。 1 案例介绍 CherryStudio …