Atcoder ABC133F - Colorful Tree 题解 主席树 + LCA

news/2025/3/31 17:47:05/文章来源:https://www.cnblogs.com/quanjun/p/18799036

题目链接:https://atcoder.jp/contests/abc133/tasks/abc133_f

题目大意:

有一棵树,顶点编号从 \(1\)\(N\)

这棵树中第 \(i\) 条边连接着顶点 \(a_i\) 和顶点 \(b_i\),其颜色和长度分别为 \(c_i\)\(d_i\)

这里每条边的颜色用介于 \(1\)\(N-1\)(包括边界值)之间的整数表示。相同的整数代表相同的颜色,不同的整数代表不同的颜色。

回答以下 \(Q\) 个查询:

查询 \(j\) (\(1 \leq j \leq Q\)): 假设颜色为 \(x_j\) 的边的长度都改变为 \(y_j\),求顶点 \(u_j\) 和顶点 \(v_j\) 之间的距离。(边的长度的改变不会影响后续的查询。)

解题思路完全参考自 Minecraft万岁 大佬的博客:https://www.luogu.com.cn/article/aw4dp6vd

我写代码的时候碰到一个比较脑抽的问题是:习惯用 d 表示深度,但是这里 edge 里也有一个 d,调了半天,然后把深度改成 depth 表示了囧

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5, maxm = 2e6 + 5;int rt[maxn], idx, ls[maxm], rs[maxm];int tcnt[maxm], tsum[maxm];void push_up(int u) {tcnt[u] = tcnt[ls[u]] + tcnt[rs[u]];tsum[u] = tsum[ls[u]] + tsum[rs[u]];
}// 多了一条颜色为 c 长度为 d 的边
void add(int c, int d, int l, int r, int u, int uu) {tcnt[u] = tcnt[uu];tsum[u] = tsum[uu];ls[u] = ls[uu];rs[u] = rs[uu];if (l == r) {tcnt[u]++;tsum[u] += d;return;}int mid = (l + r) / 2;if (c <= mid) {ls[u] = ++idx;add(c, d, l, mid, ls[u], ls[uu]);}else {rs[u] = ++idx;add(c, d, mid+1, r, rs[u], rs[uu]);}push_up(u);
}pair<int, int> query(int c, int l, int r, int u) {if (!u) return {0, 0};if (l == r) {return { tcnt[u], tsum[u] };}int mid = (l + r) / 2;return (c <= mid) ? query(c, l, mid, ls[u]) : query(c, mid+1, r, rs[u]);
}int fa[maxn][17], dis[maxn][17], dep[maxn];
int n, Q;
struct Edge { int v, c, d; };
vector<Edge> g[maxn];void dfs(int u, int p, int depth) {fa[u][0] = p;dep[u] = depth;for (auto e : g[u]) {int v = e.v, c = e.c, d = e.d;if (v == p) continue;rt[v] = ++idx;add(c, d, 1, n-1, rt[v], rt[u]);dis[v][0] = d;dfs(v, u, depth+1);}
}void check_dfs(int u, int p) {for (auto e : g[u]) {int v = e.v;if (v != p)assert(dep[v] == dep[u] + 1),check_dfs(v, u);}
}int lca(int x, int y) {if (dep[x] < dep[y]) swap(x, y);for (int i = 16; i >= 0; i--)if (dep[ fa[x][i] ] >= dep[y])x = fa[x][i];if (x == y) return x;for (int i = 16; i >= 0; i--)if (fa[x][i] != fa[y][i])x = fa[x][i], y = fa[y][i];return fa[x][0];
}// 计算从节点 x 到它的祖先节点 z 的所有边的长度总和
int get_dis(int x, int z) {int res = 0;for (int i = 16; i >= 0; i--) {if (dep[ fa[x][i] ] >= dep[z]) {res += dis[x][i];x = fa[x][i];}}return res;
}int cal(int c, int w, int x, int y) {int z = lca(x, y);int cnt = 0, sum = 0;auto pi = query(c, 1, n-1, rt[x]);cnt += pi.first;sum += pi.second;pi = query(c, 1, n-1, rt[y]);cnt += pi.first;sum += pi.second;pi = query(c, 1, n-1, rt[z]);cnt -= 2 * pi.first;sum -= 2 * pi.second;int dis1 = get_dis(x, z), dis2 = get_dis(y, z);return dis1 + dis2 - sum + cnt * w;
}int main() {scanf("%d%d", &n, &Q);for (int i = 1; i < n; i++) {int a, b, c, d;scanf("%d%d%d%d", &a, &b, &c, &d);g[a].push_back({ b, c, d });g[b].push_back({ a, c, d });}rt[1] = ++idx;dfs(1, 0, 1);check_dfs(1, 1);for (int j = 1; j <= 16; j++) {for (int i = 1; i <= n; i++) {fa[i][j] = fa[ fa[i][j-1] ][j-1];dis[i][j] = dis[i][j-1] + dis[ fa[i][j-1] ][j-1];}}while (Q--) {int c, w, x, y;scanf("%d%d%d%d", &c, &w, &x, &y);printf("%d\n", cal(c, w, x, y));}return 0;
}

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

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

相关文章

VGG

VGG 网络LRN(Local Response Normalization)来自于AlexNet现在已经不怎么使用,因为经过很多实验并没有较大的作用 conv的stride为1,padding为1 maxpool的size为2,stride为2感受野叠加 论文中一个比较重要的使用就是感受野的叠加 感受野(Receptive Field)是卷积神经网络中一…

日语声调

日语声调的记忆 方法1方法2方法3日语声调的标记方法 方法1:划线规律1:第1个音 和 第2个音不是同音 规律2:出现降音就不会升回去 规律3:“高-低”在第几个音出现,就是几型 方法2:数字

荧光灯下的“绚烂”

“绚烂”这一可以令人愉悦的词汇,在航空发动机研制过程中,却给人另外的意味。荧光检测荧光检测 荧光检测是一种在零件表面进行的无损检测,可用于检测航空发动机零部件因疲劳、撞击、机加、淬火、锻造、铸造过载等因素造成的各种裂纹、接缝等表面缺陷。 当荧光检测应用在航…

课堂里的人工智能,或者说,狂野西部闯进了教育界

诺米科托博士(Normi Coto, PhD)配图来自 Unsplash 的 Element5 Digital3 月 15 日星期六,我参加了一场名为“人文学科中的 AI”的职业发展工作坊。会场人满为患,坐满了来自弗吉尼亚州中学和高中的英语和历史老师。来自弗吉尼亚大学和朗伍德大学的教授主持了这次工作坊,主题…

LED数码管显示独立按键次数

前言 目标 2个独立按键,按下K1,数码管显示的数字加1 按下K2,数码管显示的数字减1 效果 https://www.bilibili.com/video/BV1aXo9YxEhY原理独立按键,用于控制数字的加减把完整的数字,分成若干数位显示构造一个函数 show_digit(pos,digit) , 可以在指定位置(0<=pos<=7…

Bitcoin部署到openEuler RISC-V

Bitcoin项目源码是用C++写的,我对C++以及它的编译工具又比较熟悉,这次我尝试了在openEuler RISC-V 24.09上面部署Bitcoin。网上编译Bitcoin源码的很多都是以前旧版的,旧版编译是用automake之类的工具,但是在最新版只需要用cmake就行,两者的部署方式不相同,我分别记录一下…

NVIDIA安装程序无法继续

原因 在更新驱动时,手贱,下驱动一半关闭了下载流程。导致下载失败,而且进入不了Geforece 解决方法:官网下载最新版驱动,再尝试。 如果不行,检查Windows更新,更新至最新版本 重启后如果不可行,再关闭杀毒软件,关闭防火墙,再尝试,重启再尝试。 如果还是不行,使用卸载…

锚定碳中和,三重角色重构,运营商的第四次跃迁

「 作为能源消耗大户,运营商在面对碳中和的级终命题时需要转变发展思路、转变角色定位。」5G+AI倒逼运营商基础设施建设大规模提速,运营商要更好的生存发展必须要降本提效,碳中和的大目标则要求运营商在快速发展的同时还要破解能源消耗指数级增长的魔咒——这似乎是一个不可…

SpringBoot整合RabbitMQ--Fanout模式

使用springBoot整合rabbitMQ需要事先导入相关依赖:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.bo…

查看网站支持的tls版本

f12 打开chrome 开发面板本文由 trykle 发布联系方式:QQ 294986636本文地址:https://www.cnblogs.com/trykle/p/18798939

解析PromQL并修改添加Label

最近做的项目中用到了Prometheus做预警服务,其中Prometheus使用promql语言来查询。项目中用户通过UI或者自己手动输入PromQL时候是缺少一些系统参数的,所以需要在用户输入完成以后同步到Prometheus时候将这部分缺失的信息给添加回去,这里就需要修改用户写的PromQL了。 实现思…

学习安装配置vue

1.先将nodejs下载2.在我们的安装目录下,创建名为node_cache和node_global的两个文件夹 3.打开cmd窗口,执行如下命令,将npm的全局模块目录和缓存目录配置到刚才创建的那两个目录。 npm config set prefix “D:\soft2024.7.6\nodejs\node_global” npm config set cache “D:\…