热门标签 | 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学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
  • 图数据库中的知识表示与推理机制
    本文探讨了图数据库及其技术生态系统在知识表示和推理问题上的应用。通过理解图数据结构,尤其是属性图的特性,可以为复杂的数据关系提供高效且优雅的解决方案。我们将详细介绍属性图的基本概念、对象建模、概念建模以及自动推理的过程,并结合实际代码示例进行说明。 ... [详细]
  • 本文介绍如何使用Python进行文本处理,包括分词和生成词云图。通过整合多个文本文件、去除停用词并生成词云图,展示文本数据的可视化分析方法。 ... [详细]
  • MySQL索引详解与优化
    本文深入探讨了MySQL中的索引机制,包括索引的基本概念、优势与劣势、分类及其实现原理,并详细介绍了索引的使用场景和优化技巧。通过具体示例,帮助读者更好地理解和应用索引以提升数据库性能。 ... [详细]
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 在 Flutter 开发过程中,开发者经常会遇到 Widget 构造函数中的可选参数 Key。对于初学者来说,理解 Key 的作用和使用场景可能是一个挑战。本文将详细探讨 Key 的概念及其应用场景,并通过实例帮助你更好地掌握这一重要工具。 ... [详细]
  • 不确定性|放入_华为机试题 HJ9提取不重复的整数
    不确定性|放入_华为机试题 HJ9提取不重复的整数 ... [详细]
  • 本文深入探讨了POJ2762问题,旨在通过强连通分量缩点和单向连通性的判断方法,解决有向图中任意两点之间的可达性问题。文章详细介绍了算法原理、实现步骤,并附带完整的代码示例。 ... [详细]
  • 本文详细介绍了 Java 中的 org.apache.hadoop.registry.client.impl.zk.ZKPathDumper 类,提供了丰富的代码示例和使用指南。通过这些示例,读者可以更好地理解如何在实际项目中利用 ZKPathDumper 类进行注册表树的转储操作。 ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 本文探讨了在UC浏览器中调用分享面板后,图片无法正常显示的问题,并提供了详细的解决方法和代码示例。 ... [详细]
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社区 版权所有