首页 > 其他分享 >P9432 [NAPC-#1] rStage5 - Hard Conveyors

P9432 [NAPC-#1] rStage5 - Hard Conveyors

时间:2023-09-27 18:58:53浏览次数:32  
标签:-# int res top Hard P9432 len 关键点 dis

P9432 [NAPC-#1] rStage5 - Hard Conveyors

感谢此题让我知道了 Dijkstra 的一种新用法。

题意:

给定一棵 \(n\) 个节点的无根树以及树上的 \(k\) 个关键节点,给定边的长度。有 \(q\) 次询问,每次给出 \(s,t\),问从 \(s\) 到 \(t\) 且经过至少一个关键节点的路径的最短长度。

分析:

显然经过至少一个关键节点的条件可以分为两种情况判断:

  1. 如果从 \(s\) 到 \(t\) 的简单路径上已经有关键点,那么直接输出 \(s\) 到 \(t\) 的简单路径长度即可。这个过程显然可以以 \(1\) 为根处理出每个节点 \(u\) 到节点 \(1\) 的距离 \(len_u\),那么长度 \(ans\) 就是 \(len_u+len_v-2\times len_{lca(u,v)}\)。

  2. 如果从 \(s\) 到 \(v\) 的简单路径上没有关键点,那么显然找到最近的关键点 \(v\),走到 \(v\) 再回到简单路径上的方法可以得到最优解。而不妨预处理出每个点到任意一个关键点的最短距离 \(dis\) 数组,则路径到任意关键点的最短距离就可以定义为简单路径上 \(dis\) 数组的最小值 \(mindis\),由此答案只需要在 \(ans\) 的基础上再加上 \(2\times mindis\)。而多次查询路径上区间有关信息的问题显然可以用线段树 \(+\) 树链剖分实现,那么关键就是如何计算每个点到任意一个关键点的最短距离

这时候就需要 Dijkstra 的经典(神奇逆天)多源最短路写法了:将每个关键点的初始 \(dis\) 均设为 \(0\),再跑普通的堆优化 Dijkstra,此时 \(dis\) 数组存储的就是每个点到任意一个关键点的最短距离了。

核心代码如下:

priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;

inline void dij() {
	memset(dis, 0x3f, sizeof dis);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= k; i++) {
		dis[p[i]] = 0;
		q.push({0, p[i]});
	}
	while (!q.empty()) {
		auto u = q.top().second;
		q.pop();

		if (vis[u]) continue;
		vis[u] = 1;

		for (auto i : G[u]) {
			int v = i.first, w = i.second;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				q.push({dis[v], v});
			}
		}
	}
}

剩下的就是经典的普通树剖维护 \(dis\) 数组的区间最小值了。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 1e5 + 5;
int n, m, k;
vector<pair<int, int> > G[maxn];
struct data {
	int l, r, dat;
} t[maxn << 2];
int dep[maxn], fa[maxn], siz[maxn], son[maxn], top[maxn], dfn[maxn], rk[maxn], cnt;
int len[maxn];
int dis[maxn], p[maxn];
bool vis[maxn];
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;

inline void dfs1(int u, int f) {
	dep[u] = dep[f] + 1;
	siz[u] = 1;
	for (auto i : G[u]) {
		int v = i.first, w = i.second;
		if (v == f) continue;
		fa[v] = u;
		len[v] = len[u] + w;
		dfs1(v, u);
		siz[u] += siz[v];
		if (siz[son[u]] < siz[v]) son[u] = v;
	}
}

inline void dfs2(int u, int tp) {
	top[u] = tp;
	dfn[u] = ++cnt;
	rk[cnt] = u;
	if (!son[u]) return;
	dfs2(son[u], tp);
	for (auto i : G[u]) {
		int v = i.first;
		if (v == fa[u] or v == son[u]) continue;
		dfs2(v, v);
	}
}

inline void build(int p, int l, int r) {
	t[p].l = l, t[p].r = r;
	if (l == r) {
		t[p].dat = dis[rk[l]];
		return;
	}
	int mid = (l + r) >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
	t[p].dat = min(t[p << 1].dat, t[p << 1 | 1].dat);
}

inline int query(int p, int l, int r) {
	if (l <= t[p].l and t[p].r <= r) return t[p].dat;
	int mid = (t[p].l + t[p].r) >> 1, res = 0x3f3f3f3f;
	if (l <= mid) res = min(res, query(p << 1, l, r));
	if (mid < r) res = min(res, query(p << 1 | 1, l, r));
	return res;
}

inline void dij() {
	memset(dis, 0x3f, sizeof dis);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= k; i++) {
		dis[p[i]] = 0;
		q.push({0, p[i]});
	}
	while (!q.empty()) {
		auto u = q.top().second;
		q.pop();

		if (vis[u]) continue;
		vis[u] = 1;

		for (auto i : G[u]) {
			int v = i.first, w = i.second;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				q.push({dis[v], v});
			}
		}
	}
}

inline int get(int u, int v) {
	int res = 0x3f3f3f3f, ans = 0, uu = u, vv = v;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		res = min(res, query(1, dfn[top[u]], dfn[u]));
		u = fa[top[u]];
	}
	if (dep[u] > dep[v]) swap(u, v);
	res = min(res, query(1, dfn[u], dfn[v]));
	ans = len[uu] + len[vv] - len[u] * 2;
	return ans + res * 2;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	cin >> n >> m >> k;
	for (int i = 1; i < n; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		G[u].push_back({v, w});
		G[v].push_back({u, w});
	}
	for (int i = 1; i <= k; i++) cin >> p[i];
	dij();
	dfs1(1, 1);
	dfs2(1, 1);
	build(1, 1, n);
	for (int i = 1; i <= m; i++) {
		int u, v;
		cin >> u >> v;
		cout << get(u, v) << "\n";
	}
}

标签:-#,int,res,top,Hard,P9432,len,关键点,dis
From: https://www.cnblogs.com/George-Pig-Orz/p/17733423.html

相关文章

  • 接口自动化--postman(3)高级用法,全局变量和环境变量
    Postman提供了GUI界面的变量管理窗口,可以管理全局变量和环境变量全局变量:整个Postman都能使用的变量环境变量:选中环境后,才会全局生效的变量,叫做环境变量环境变量作用:可以通过变量进行参数化,方便集中管理测试数据;同时环境变量还可以起到快速切换环境的作用。Postman界面......
  • 【详解】Spring Boot + Mybatis-Plus实现CRUD,轻松玩转接口操作!
    ......
  • Threejs -- TweenJS自定义flyTo函数
    TweenJS参考文档笔记末尾附自定义flyTo函数动画库tweenjs简介和引入项目TweenJS是一个有javascript语言编写的补间动画库,如果需要tweenjs辅助你生成动画,对于任何前端web项目,你都可以选择tweenjs库。如果你是用three.js开发web3d项目,使用tween.js辅助three.js生成动画效果......
  • MySQL运维2-主从复制
    一、主从复制概念主从复制是指将主数据库的DDL和DML操作通过二进制日志传到从服务器中,然后在从服务器上对这些日志重新执行也叫重做,从而使得从数据库和主库的数据保持同步。MySQL支持一台主库同时向多台从库进行赋值,从库同时也可以作为其他从服务器的主库,实现链式复制。......
  • 案例实操基础版--加载数据+数据清洗(5W条数据)
    我看到了这个跟着实操一下!1、加载数据(已经提供了csv文件)建库建表--->这个比较简单,根据文件的字段名创建合适的表;createtablemsg(msg_timestringcomment"消息发送时间",sender_namestringcomment"发送人昵称",sender_accountstringcomment"发送人帐......
  • 记录--Vue3 + Fabricjs 定制国庆专属头像
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助生在国旗下,长在春风里!国庆将至,采黎为大家带来定制头像2.0(国庆头像),让我们用代码的形式为祖国庆生!欢迎大家点赞收藏加关注哦前言想看效果或者想定制春节头像的小伙伴请直奔效果区域;想一睹定制头像2.0小工具的......
  • golang-waitgroup
    说明golang通过waitgroup来实现并发控制,用法跟java的CountDownLatch 效果一样 WaitGroup的使用场景和方法我们通过goroutine运行一个或者一组任务,需要关心这组任务执行完了进行通知WaitGroup如同它的字面意思,就是等待一组goroutine运行完成,主要有三个方法组成:Add(de......
  • 中国电信 NB-IoT 翻频方案及操作指导
    中国电信800MNB-IoT翻频方案说明:翻频前频点分布如下图所示,对应中心频点为879.4/.6/.8MHz或879.5/.7/.9MHz翻频前频点信息:BAND52504,2506,2508  翻频后频点下移分布如下图所示,对应中心频点为869.1/869.3/869.5MHz位置,翻频后频点信息:BAND52401,2403,2405 ......
  • 最新国产低功耗,远距离终端芯片-PAN3029
      磐启微持续不断通过Chirp技术创新推动窄带物联网发展。ChirpIoT™终端芯片方面,磐启微首先推出了PAN3028/3031,此后又推出更低功耗、更高速率的PAN3029,针对下一代终端芯片将会往更低功耗、更高速率、更优灵敏度方向发展。ChirpIoT™网关系统,磐启微已经推出了DTM-CC016A,关于下一......
  • JavaWeb--文件上传和下载
    上传文件如何实现文件上传要实现Web开发中的文件上传功能,通常只需完成两步操作1、在Web界面中添加上传输入项2、在Servlet中读取上文件的表单页面,并保存到硬盘中文件上传的相关APIFiletem接口它只要用于Commons-FileUpload组件当中,主要是封装单个表单字段元素。DiskFiletemFacto......