当前位置: 首页 > news >正文

NOIP2015提高组.运输计划

题目

521. 运输计划
在这里插入图片描述

算法标签: 树上倍增, l c a lca lca, 前缀和, 树上差分, 二分

思路

注意到答案是具有二分性质的, 对于某个时间 m i d mid mid假设是最优答案, 小于该时间是不可以的, 但是大于该时间是可行的, 因此可以二分答案

这样就将问题转化为, 对于给定的时间 m i d mid mid, 将树中的一条边权变为 0 0 0, 所有的运输路线耗时是否 ≤ m i d \le mid mid
可以将所有运输的路线分为两类, 一种是运输时间 ≤ m i d \le mid mid的, 这种路线不要需要删除边
但是还有一种路线是 > m i d > mid >mid, 对于这些路线需要找个这些路线的公共边, 将这个公共边的权值变为 0 0 0, 但是直接枚举所有的边和路线会超时, 因此需要进行优化

可以在所有路线上的边 + 1 + 1 +1, 最终结果就是公共边被加了 t t t次, t t t是大于 m i d mid mid的路线的数量, 这样就找到了这个边, 利用树上差分, 实现对每个边 + 1 +1 +1的操作

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

const int N = 300010, M = N << 1, K = 19;

int n, m;
int head[N], ed[M], ne[M], w[M], idx;
int fa[N][K], depth[N], d[N];
struct Path {
	int u, v, p, d;
} path[N];
int s[N];

void add(int u, int v, int val) {
	ed[idx] = v, ne[idx] = head[u], w[idx] = val, head[u] = idx++;
}

void dfs(int u, int pre, int dep) {
	depth[u] = dep;

	for (int i = head[u]; ~i; i = ne[i]) {
		int v = ed[i];
		if (v == pre) continue;
		fa[v][0] = u;
		for (int k = 1; k < K; ++k) fa[v][k] = fa[fa[v][k - 1]][k - 1];
		d[v] = d[u] + w[i];
		dfs(v, u, dep + 1);
	}
}

int lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	for (int k = K - 1; k >= 0; --k) {
		if (depth[fa[u][k]] >= depth[v]) {
			u = fa[u][k];
		}
	}

	if (u == v) return v;
	for (int k = K - 1; k >= 0; --k) {
		if (fa[u][k] != fa[v][k]) {
			u = fa[u][k];
			v = fa[v][k];
		}
	}

	return fa[u][0];
}

void dfs_sum(int u, int pre) {
	for (int i = head[u]; ~i; i = ne[i]) {
		int v = ed[i];
		if (v == pre) continue;
		dfs_sum(v, u);
		s[u] += s[v];
	}
}

bool check(int mid) {
	memset(s, 0, sizeof s);
	int c = 0, max_d = 0;
	for (int i = 0; i < m; ++i) {
		auto [u, v, p, val] = path[i];
		if (val > mid) {
			c++;
			max_d = max(max_d, val);
			s[u]++;
			s[v]++;
			s[p] -= 2;
		}
	}

	if (c == 0) return true;

	dfs_sum(1, -1);

	for (int u = 2; u <= n; ++u) {
		if (s[u] == c && max_d - (d[u] - d[fa[u][0]]) <= mid) {
			return true;
		}
	}

	return false;
}

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

	memset(head, -1, sizeof head);

	cin >> n >> m;
	for (int i = 0; i < n - 1; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		add(u, v, w), add(v, u, w);
	}

	dfs(1, -1, 1);

	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		int p = lca(u, v);
		int dis = d[u] + d[v] - 2 * d[p];
		path[i] = {u, v, p, dis};
	}

	int l = 0, r = 3e8;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}

	cout << l << "\n";
	return 0;
}

* v e c t o r vector vector存邻接表会超时

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

typedef pair<int, int> PII;
const int N = 300010, M = N << 1, K = 19;

int n, m;
vector<PII> head[N];
int fa[N][K], depth[N], d[N];
struct Path {
	int u, v, p, d;
};
vector<Path> path;
int s[M];

void init() {
	path.resize(m + 1);
}

void add(int u, int v, int w) {
	head[u].push_back({v, w});
}

void dfs(int u, int pre, int dep) {
	depth[u] = dep;
	for (auto [v, w] : head[u]) {
		if (v == pre) continue;
		fa[v][0] = u;
		for (int k = 1; k < K; ++k) fa[v][k] = fa[fa[v][k - 1]][k - 1];
		d[v] = d[u] + w;
		dfs(v, u, dep + 1);
	}
}

int lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	for (int k = K - 1; k >= 0; --k) {
		if (depth[fa[u][k]] >= depth[v]) {
			u = fa[u][k];
		}
	}

	if (u == v) return u;
	for (int k = K - 1; k >= 0; --k) {
		if (fa[u][k] != fa[v][k]) {
			u = fa[u][k];
			v = fa[v][k];
		}
	}

	return fa[u][0];
}

void dfs_sum(int u, int fa) {
	for (auto [v, w] : head[u]) {
		if (v == fa) continue;
		dfs_sum(v, u);
		s[u] += s[v];
	}
}

bool check(int mid) {
	memset(s, 0, sizeof s);
	int cnt = 0, max_d = 0;
	for (auto [u, v, p, dis] : path) {
		if (dis > mid) {
			cnt++;
			s[u]++;
			s[v]++;
			s[p] -= 2;
			max_d = max(max_d, dis);
		}
	}

	if (cnt == 0) return true;

	dfs_sum(1, -1);

	for (int u = 2; u <= n; ++u) {
		if (s[u] == cnt && max_d - (d[u] - d[fa[u][0]]) <= mid) return true;
	}

	return false;
}

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

	cin >> n >> m;

	init();

	for (int i = 0; i < n - 1; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		add(u, v, w), add(v, u, w);
	}

	dfs(1, -1, 1);

	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		int p = lca(u, v);
		path[i] = {u, v, p, d[u] + d[v] - 2 * d[p]};
	}

	int l = 0, r = 3e8;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}

	cout << l << "\n";
	return 0;
}

文章转载自:

http://F11A4Foc.rzysq.cn
http://D3vwTgq1.rzysq.cn
http://RoY1jRSy.rzysq.cn
http://pDW2chPj.rzysq.cn
http://FOU7dSLv.rzysq.cn
http://psWtAsVt.rzysq.cn
http://X63IoZSW.rzysq.cn
http://fqM2P6zX.rzysq.cn
http://tF2xxVgP.rzysq.cn
http://AMDtNVSa.rzysq.cn
http://PHv0GApK.rzysq.cn
http://wHnZjm6Y.rzysq.cn
http://PnJTD8T9.rzysq.cn
http://kMRuBUpm.rzysq.cn
http://ip9bQn9x.rzysq.cn
http://F9q3Knv4.rzysq.cn
http://zzsOE5a7.rzysq.cn
http://2VkVsKi4.rzysq.cn
http://7v0P7QoK.rzysq.cn
http://8nxjEUZp.rzysq.cn
http://lyapJThl.rzysq.cn
http://kfu0fTDn.rzysq.cn
http://QxE26yzp.rzysq.cn
http://jxY56mYS.rzysq.cn
http://r5sqxVkw.rzysq.cn
http://9ilJQw4o.rzysq.cn
http://g17msgmO.rzysq.cn
http://sX8wvgv4.rzysq.cn
http://tAwjbcNc.rzysq.cn
http://4xaH2i7A.rzysq.cn
http://www.dtcms.com/a/127815.html

相关文章:

  • Web 项目实战:构建属于自己的博客系统
  • 雷池WAF防火墙如何构筑DDoS防护矩阵?——解读智能语义解析对抗新型流量攻击
  • 数据库预热
  • PostIn安装及入门教程
  • 初识华为防火墙
  • 如何解决DDoS攻击问题 ?—专业解决方案深度分析
  • 嵌入式硬件篇---单片机周期
  • 猫咪如厕检测与分类识别系统系列【四】融合检测日志输出及前端展示界面制作
  • 内网邮箱服务器搭建-详解
  • LabVIEW往复式压缩机管路故障诊断系统
  • 消防设施操作员岗位注意事项有哪些?
  • 《基于AI识别的雾炮联动:堆场扬尘治理新利器》
  • DeepSeek使用001:Word中配置DeepSeek AI的V3和R1模型
  • 【Hadoop入门】Hadoop生态之Flume简介
  • Android应用开发指南
  • 在WPS中通过JavaScript宏(JSA)调用DeepSeek官方API自动识别标题级别和目录
  • 在Vue项目的引入meting-js音乐播放器插件
  • K8s 集群网络疑难杂症:解决 CNI 网络接口宕机告警的完整指南
  • 09-设计模式 企业场景 面试题-mk
  • 小刚说C语言刷题——第22讲 二维数组
  • JS【详解】迭代器 Iterator(含可迭代对象、同步迭代器、异步迭代器等)
  • @PKU秋招互联网产品经理求职分享
  • 永磁同步电机控制算法--基于有功功率扰动的频率补偿IF控制
  • 网络1 网络设备
  • opencv-python(图像基础)
  • 解析医疗器械三大文档:DHF、DMR与DHR
  • 蓝桥杯之门牌
  • SQL问题分析与诊断(8)——分析方法1
  • Sentinel核心算法解析の漏桶算法
  • Docker的镜像构建