热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

洛谷P4116树上操作:颜色变换与路径查询

本题涉及一棵由N个节点组成的树(共有N-1条边),初始时所有节点均为白色。题目要求处理两种操作:一是改变某个节点的颜色(从白变黑或从黑变白);二是查询从根节点到指定节点路径上的第一个黑色节点,若无则输出-1。

该问题的核心在于对树结构进行高效的管理和查询。具体来说,我们使用树链剖分(Heavy-Light Decomposition, HLD)结合线段树来实现高效的操作和查询。


题目描述:


给定一棵由N个节点组成的树(N-1条边),每个节点初始为白色。需要支持以下两种操作:



  • 0 i:将第i个节点的颜色反转(白变黑或黑变白)。

  • 1 v:询问从根节点到第v个节点的路径上第一个遇到的黑色节点编号,如果路径上没有黑色节点,则输出-1。


输入格式:


第一行包含两个整数N和Q,分别表示节点数量和操作数量。接下来N-1行每行两个整数u和v,表示一条连接u和v的无向边。最后Q行,每行一个操作0 i1 v


输出格式:


对于每个1 v操作,输出结果。


解决方案:


为了高效处理这些操作,我们可以使用树链剖分(HLD)配合线段树。具体步骤如下:



  1. 通过两次深度优先搜索(DFS)完成树链剖分,记录每个节点的重儿子、轻儿子、深度等信息。

  2. 构建线段树,维护每个区间的黑色节点信息。若区间内存在黑色节点,则记录其位置;否则记录为-1。

  3. 对于每个0 i操作,更新对应节点在链上的颜色,并在线段树中同步更新。

  4. 对于每个1 v操作,通过树链剖分将路径分解成若干段,在线段树中查询每段的第一个黑色节点,并合并结果。


代码实现:


#include 
#include
#include
#include
#define MAXN 100233
using namespace std;

int n, m;
int tot = 0, cnt = 0;
struct Edge {
int nex, to;
} e[MAXN <<1];
int h[MAXN], fa[MAXN], top[MAXN], son[MAXN], dep[MAXN], siz[MAXN], id[MAXN];
int w[MAXN] = {}, ans[MAXN <<2], nid[MAXN];

inline void add(int x, int y) {
e[++tot].to = y;
e[tot].nex = h[x];
h[x] = tot;
}

void dfs_first(int x, int f, int dept) {
dep[x] = dept;
fa[x] = f;
siz[x] = 1;
int maxn = -1;
for (int i = h[x], y; i; i = e[i].nex) {
y = e[i].to;
if (y == f) continue;
dfs_first(y, x, dept + 1);
siz[x] += siz[y];
if (siz[y] > maxn) {
son[x] = y;
maxn = siz[y];
}
}
}

void dfs_second(int x, int ft) {
top[x] = ft;
id[x] = ++cnt;
nid[cnt] = x;
if (!son[x]) return;
dfs_second(son[x], ft);
for (int i = h[x], y; i; i = e[i].nex) {
y = e[i].to;
if (y == son[x] || y == fa[x]) continue;
dfs_second(y, y);
}
}

#define leftson cur <<1
#define rightson cur <<1 | 1
#define mid ((l + r) >> 1)
#define push_up if (ans[leftson] != -1) { ans[cur] = ans[leftson]; return; } if (ans[rightson] != -1) { ans[cur] = ans[rightson]; return; } ans[cur] = -1

void build(int cur, int l, int r) {
if (l == r) {
ans[cur] = -1;
return;
}
build(leftson, l, mid);
build(rightson, mid + 1, r);
push_up;
}

void change(int adn, int cur, int l, int r) {
if (l == r) {
if (ans[cur] != -1) {
ans[cur] = -1;
return;
}
ans[cur] = l;
return;
}
if (adn <= mid) change(adn, leftson, l, mid);
else change(adn, rightson, mid + 1, r);
push_up;
}

int query(int ql, int qr, int cur, int l, int r) {
if (ql <= l && r <= qr) {
return ans[cur];
}
if (ql <= mid) {
int ans_a = query(ql, qr, leftson, l, mid);
if (ans_a != -1) return ans_a;
}
if (qr > mid) return query(ql, qr, rightson, mid + 1, r);
return -1;
}

int query_(int x, int y) {
int ans_a, ans_b = -1;
while (top[x] != top[y]) {
if (dep[top[x]] ans_a = query(id[top[x]], id[x], 1, 1, n);
if (ans_b == -1) ans_b = ans_a;
else if (ans_a != -1) ans_b = min(ans_a, ans_b);
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
ans_a = query(id[x], id[y], 1, 1, n);
if (ans_b == -1) ans_b = ans_a;
else if (ans_a != -1) ans_b = min(ans_a, ans_b);
return ans_b;
}

int main() {
scanf("%d%d", &n, &m);
int x, y;
for (int i = 1; i scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs_first(1, 0, 1);
dfs_second(1, 1);
build(1, 1, n);
for (int i = 1, answer; i <= m; i++) {
scanf("%d%d", &x, &y);
if (!x) {
change(id[y], 1, 1, n);
continue;
}
answer = query_(1, y);
if (answer == -1) printf("-1\n");
else printf("%d\n", nid[answer]);
}
return 0;
}

推荐阅读
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • MySQL索引详解与优化
    本文深入探讨了MySQL中的索引机制,包括索引的基本概念、优势与劣势、分类及其实现原理,并详细介绍了索引的使用场景和优化技巧。通过具体示例,帮助读者更好地理解和应用索引以提升数据库性能。 ... [详细]
  • 本文介绍如何使用 Python 将一个字符串按照指定的行和元素分隔符进行两次拆分,最终将字符串转换为矩阵形式。通过两种不同的方法实现这一功能:一种是使用循环与 split() 方法,另一种是利用列表推导式。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • Java 中 Writer flush()方法,示例 ... [详细]
  • Java 中的 BigDecimal pow()方法,示例 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
author-avatar
qlongjun
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有