热门标签 | 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;
}

推荐阅读
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • This document outlines the recommended naming conventions for HTML attributes in Fast Components, focusing on readability and consistency with existing standards. ... [详细]
  • 使用Python在SAE上开发新浪微博应用的初步探索
    最近重新审视了新浪云平台(SAE)提供的服务,发现其已支持Python开发。本文将详细介绍如何利用Django框架构建一个简单的新浪微博应用,并分享开发过程中的关键步骤。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • Java 中的 BigDecimal pow()方法,示例 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
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社区 版权所有