P9678 题解

news/2025/1/21 21:50:17/文章来源:https://www.cnblogs.com/CTHOOH/p/18684414
题意

给定一棵 \(n\) 个点的树 \(T\),边有边权。现在有 \(q\) 组询问,每组询问给出 \(l, r\),求出:

\[\min_{l \le i < j \le r} \operatorname{dist}(i, j) \]

\(n \le 2 \times 10^5\), \(q \le 10^6\), \(1 \le w \le 10^9\)

由于与路径长度有关,所以考虑点分治或者 LCA。由于笔者思考 LCA 无果所以这篇题解的做法是点分治。

考虑点分治,对于一个分治过程,我们考虑计算出分治块内点对对询问的贡献。对于分治块内的点 \(x\),记 \(x\) 到分治重心的距离为 \(d_x\)。根据 Shik and Travel 的一个 trick,考虑只记录有用的点对,什么点对是有用的?对于点对 \((x, y)\),如果存在 \((x', y')\) 使得 \(x \le x' < y' \le y\)\(d_x + d_y \ge d_{x'} + d_{y'}\),那么 \((x, y)\) 是有用的。因为点对 \((x', y')\) 能贡献到更多的询问,并且其 \(\operatorname{dist}\) 还更小,所以 \((x, y)\) 可以被 \((x', y')\) 完全代替。当分治块内不存在更好的点对时,\((x, y)\) 就是有用的。

同时,这里不对每个点来自哪个分治重心的儿子区分,因为如果两个点属于同一个子树,在继续往下分治时这两个点的贡献会被重新计算。在当前分治过程中,即使将两点距离计算错误也不会对最终答案产生影响。

有用的点对有多少呢?观察到当 \(y' = y\) 时,有 \(d_x < d_{x'}\),当 \(x' = x\) 时,有 \(d_y < d_{y'}\),所以有:\(\max(d_x, d_y) < \min_{i = x + 1}^{y - 1} d_i\)。于是我们有了一个找出所有有用点对的方法:将所有点按照编号从小到大排成一个序列,对于点 \(x\),找到左边第一个满足 \(d_l \le d_x\)\(l\) 和右边第一个满足 \(d_r \le d_x\)\(r\)\((x, l)\)\((x, r)\) 就是两个有用的点对。根据这个方法,我们同样证明了有用的点对数量是 \(\mathcal{O}(s)\) 的,其中 \(s\) 是分治块大小,总点对数量就是 \(\mathcal{O}(\sum s) = \mathcal{O}(n \log n)\)

现在问题转化成对于每个询问 \((l, r)\),找到 \(l \le x < y \le r\) 的最近有用点对,按 \(l\) / \(x\) 从大到小排序之后,扫描线+树状数组即可。总时间复杂度 \(\mathcal{O}(n \log^2 n + q\log n)\)

代码
#include <bits/stdc++.h>using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;constexpr int N = 2E5 + 5, Q = 1E6 + 5;int n, q;
std::vector<std::array<int, 2>> adj[N];int k;
struct Data {int x, y;i64 d;int type;constexpr bool operator<(const Data& w) const {return x == w.x ? y == w.y ? type < w.type : y < w.y : x > w.x;}
} a[N * 60 + Q];bool vis[N];
int siz[N], maxs[N];
int dsum, root;
i64 d[N];i64 ans[Q];void getroot(int x, int par) {siz[x] = 1;maxs[x] = 0;for (auto [y, z] : adj[x]) {if (y == par || vis[y]) {continue;}d[y] = d[x] + z;getroot(y, x);siz[x] += siz[y];maxs[x] = std::max(maxs[x], siz[y]);}maxs[x] = std::max(maxs[x], dsum - siz[x]);if (!root || maxs[root] > maxs[x]) {root = x;}
}
void solve(int x, int nsum) {root = 0;dsum = nsum;getroot(x, x);vis[x = root] = 1;d[root] = 0;getroot(x, x);std::vector<std::pair<int, i64>> vec;auto dfs = [&](auto &&self, int x, int par) -> void {vec.push_back({x, d[x]});for (auto [y, z] : adj[x]) {if (!vis[y] && y != par) {self(self, y, x);}}} ;dfs(dfs, x, x);int m = vec.size();std::sort(vec.begin(), vec.end());std::stack<int> st;auto push = [&]() {for (int i = 0; i < m; ++i) {while (!st.empty() && vec[st.top()].second >= vec[i].second) {a[++k] = {vec[st.top()].first, vec[i].first, vec[st.top()].second + vec[i].second, 0};st.pop();}st.push(i);}while (!st.empty()) {st.pop();}} ;push();std::reverse(vec.begin(), vec.end());push();for (auto [y, z] : adj[x]) {if (!vis[y]) {solve(y, siz[y]);}}
}struct Fenwick {i64 c[N];Fenwick() {for (int i = 0; i < N; ++i) {c[i] = 1E15;}}void insert(int x, i64 val) {for (; x <= n; x += x & -x)c[x] = std::min(c[x], val);}i64 query(int x) {i64 res = 1E15;for (; x; x -= x & -x) {res = std::min(res, c[x]);}return res;}
} fen;int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cin >> n;for (int i = 1; i < n; ++i) {int u, v, w;std::cin >> u >> v >> w;adj[u].push_back({v, w});adj[v].push_back({u, w});}solve(1, n);for (int i = 1; i <= k; ++i) {if (a[i].x > a[i].y) std::swap(a[i].x, a[i].y);}std::cin >> q;for (int i = 1; i <= q; ++i) {int l, r;std::cin >> l >> r;a[++k] = {l, r, i, 1};}std::sort(a + 1, a + 1 + k);for (int i = 1; i <= k; ++i) {if (a[i].type == 1) ans[a[i].d] = fen.query(a[i].y);else fen.insert(a[i].y, a[i].d);}for (int i = 1; i <= q; ++i) {std::cout << (ans[i] == 1E15 ? -1 : ans[i]) << "\n";}return 0;
}

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

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

相关文章

《操作系统真相还原》实验记录2.7——生产者与消费者问题

本节实现内容如下: ① 环形缓存区的结构体创建; ② 环形键盘缓冲区的创建; ③ 生产者消费者问题剖析;一、生产者与消费者问题简述我们知道,在计算机中可以并行多个线程,当它们之间相互合作时,必然会存在共享资源的问题,这是通过“线程同步”来解决的,而诠释“线程同步…

CTF-web第一步!

本次的题比较简单,适合我这种入门学者。CTF菜狗杯的web2 c0me_t0_s1gn。进入靶场打开F12会得到前一半。在控制台复制函数give_flag()会得到另一半。 这样就完成了。

P1183 多边形的面积-向量的用法

原题链接 https://www.luogu.com.cn/problem/P1183 题目描述 给出一个没有缺口的简单多边形,它的边是垂直或者水平的,要求计算多边形的面积。 xOy 的笛卡尔平面上,它所有的边都平行于两条坐标轴之一。然后按逆时针方向给出各顶点的坐标值。所有的坐标值都是整数,因此多边形…

蓄水池漂浮物识别摄像机

蓄水池漂浮物识别摄像机具有高效的图像识别功能。通过高清晰度的摄像头捕捉到蓄水池表面的图像,并通过人工智能技术进行快速准确的漂浮物识别。这种摄像机可以自动检测出池面上的漂浮物,并生成相应报警信息。该摄像机支持多种智能算法分析,并通过智能算法对数据进行综合分析…

行为智能识别摄像机

行为智能识别摄像机通过结合人工智能技术和监控技术,实现了对各种行为动作的自动识别和分析,在提高安全性、减少事故发生率方面具有重要意义。随着科技的不断进步和应用范围的扩大,相信这种先进设备将会在更多领域得到广泛应用。行为智能识别摄像机是一种结合了人工智能技术…

AI人数智能统计监测摄像头

AI人数智能统计监测摄像头具有高效的图像识别功能。通过先进的图像处理算法,可以快速准确地识别出场景中的人群,并进行实时统计。无论是密集的人流场所还是较为稀疏的区域,这种摄像头都能够精准地进行人数统计,为管理者提供重要参考信息。AI人数智能统计监测摄像头具有实时…

Android 中的卡顿丢帧原因概述 - 方法论

Android 手机使用中的卡顿问题 , 一般来说手机厂商和 App 开发商都会非常重视 , 所以不管是手机厂商还是 App 开发者 , 都会对卡顿问题非常重视 , 内部一般也会有专门的基础组或者优化组来进行优化 . 目前市面上有一些非常棒的第三方性能监控工具 , 比如腾讯的 Matrix ; 手机厂…

JavaScript的常用库 —— jQuery

利用JS去操控HTML和CSS,常用库之jQuery ฅʕ•̫͡•ʔฅjQuery用来更加方便地去控制前端的HTML标签和CSS属性。使用方式:1. 直接在<head>元素中添加: <script src="https://cdn.acwing.com/static/jquery/js/jquery-3.3.1.min.js"></script> 2…

2 FreeRTOS移植

2 FreeRTOS移植 2.1 源码基本认识获取源码。官网地址:FreeRTOS™ - FreeRTOS™ 源码内文件结构:1) FreeRTOS文件夹结构2) Source文件夹结构3) portable文件夹结构 portable文件夹里面有编译器、内核环境可以选择。其中keil是我们使用的编译器类型,但Keil文件夹里只有一个…

22蓝帽初赛

参考wp:http://mp.weixin.qq.com/s?__biz=Mzk0MTQzNjIyNg==&mid=2247487196&idx=1&sn=48094c5a78749b45c3598ed51a5df0e3&chksm=c3901b8acd56bc2d1d06b323e9d1e86b90048a35dc3b3301b60bb1f488a764f0b52ebc490113&mpshare=1&scene=23&srcid=01218…

【Azure APIM】APIM服务配置网络之后出现3443端口不通,Management Endpoint不健康状态

如果没有关联的网络安全组,则阻止所有网络流量通过子网和网络接口。问题描述 APIM服务在配置网络之后,查看网络状态发现Management Endpoint是不健康状态, 提示无法连接到3443端口。错误消息: Failed to connect to management endpoint at xxxxxxxx.management.azure-api.…

【模拟电子技术】11-放大电路的性能指标

【模拟电子技术】11-放大电路的性能指标通过输入,输出侧的各一个电容来到输入纯交流,输出纯交流Ui变化引起UBE变化,UBE变化引起IB变化,IB变化引起IC变化,IC变化引起UCE变化,UCE变化引起Uo变化关于输入,输出等效电路的问题: 输入电阻Ri越大越好还是越小越好?当然是越大…