【Codeforces Round #406 (Div. 1) B. Legacy】(线段树 | 优化建图)

这篇文章详细讲解了如何在C++中使用邻接表和优先队列实现Dijkstra算法,以找到两点之间的最短路径。
摘要由CSDN通过智能技术生成

#include <array>
#include <queue>
#include <limits>
#include <cstdio>
#include <bitset>
#include <vector>
#include <utility>
#include <algorithm>
constexpr auto __MAX__ { static_cast<int>(1e6) };
constexpr int  FORWARD { 0 };
constexpr int  REVERSE { 1 };
typedef struct
__Edge__{
	int refer;
	int next;
	int weigth;
} Edge;

template <typename __FROM__, typename __TO__>
struct Arc {
	__FROM__ from;
	__TO__ to;
	int weight;
};

typedef struct __Path__ {
	int distance 	{};
	int numb        {};
	constexpr bool operator<(const __Path__ & other) noexcept
	{ return distance < other.distance; }
} Path;

typedef struct __Range__ {
	int first;
	int last;

	constexpr bool single() noexcept
	{ return first + 1 == last; }

	constexpr int middle() noexcept
	{ return (first + last) / 2; }

	constexpr __Range__ left_partitial() noexcept
	{ return { first, middle() }; }

	constexpr __Range__ right_partitial() noexcept
	{ return { middle(), last }; }

	constexpr bool contain(const __Range__ & other) noexcept
	{ return first <= other.first && other.last <= last; }
	
	constexpr int length() noexcept
	{ return last - first; }
} Range;

int 	N {};
int     Q {};
int     S {};
int serial {};
std::vector<Edge>					edges {};
std::array<int, __MAX__ << 2 | 1> 	head {};
std::array<int, __MAX__ << 2 | 1> 	numb[2u] {};
std::bitset<__MAX__>       			visited {};
std::array<int, __MAX__>            distance {};

constexpr auto left(int index) 	noexcept { return index << 1; }
constexpr auto right(int index) noexcept { return index << 1 | 1; }

void connect(Arc<int, int> arc, int direction) noexcept {
	auto [from, to, weight] = arc;
	if(direction == REVERSE) std::swap(from, to);
	auto temporary { static_cast<int>(edges.size()) };
	edges.emplace_back(to, head[from], weight);
	head[from] = temporary;
}

void build(Range shrink, int index, int direction) noexcept {
	if(shrink.single())
		return (void) (numb[direction][index] = shrink.first);
	numb[direction][index] = ++ serial;
	build(shrink.left_partitial(), left(index), direction);
	build(shrink.right_partitial(), right(index), direction);
	connect((Arc<int, int>){numb[direction][index], numb[direction][left(index)], 0}, direction);
	connect((Arc<int, int>){numb[direction][index], numb[direction][right(index)], 0}, direction);
}

void update(Arc<int, Range> arc, Range shrink, int index, int direction) noexcept {
	auto [integer, range, weight] = arc;
	if(range.contain(shrink))
		return (void) connect((Arc<int, int>){ integer, numb[direction][index], weight }, direction);
	if(range.first < shrink.middle()) update(arc, shrink.left_partitial(), left(index), direction);
	if(range.last >= shrink.middle()) update(arc, shrink.right_partitial(), right(index), direction);
}

void operation(int op) {
	if(op == 1) {
		int from 	{};
		int	to  	{};
		int	weight	{};
		std::scanf("%d%d%d", &from, &to, &weight);
		connect((Arc<int, int>) {from, to, weight}, FORWARD);
		return;
	}
	int point   {},
		weight  {};
	Range range {};
	std::scanf("%d%d%d%d", &point, &range.first, &range.last, &weight);
	if(op == 2)
		update((Arc<int, Range>) {point, range, weight}, (Range) {1, N}, 1, FORWARD);
	else
		update((Arc<int, Range>) {point, range, weight}, (Range) {1, N}, 1, REVERSE);
}

void dijstra(int source) {
	std::priority_queue<Path> heap {};
	distance[source] = 0;
	heap.emplace(0, source);
	while(! heap.empty()) {
		auto [current_numb, current_distance] = heap.top();
		heap.pop();
		if(visited[current_numb]) continue;
		visited[current_numb] = 1;
		for(int i {head[current_numb]}; ~i; i = edges[i].next) {
			auto [refer, dummy_next, weight] = edges[i];
			if(distance[refer] > distance[current_numb] + weight) {
				distance[refer] = distance[current_numb] + weight;
				heap.emplace(distance[refer], refer);
			}
		}
	}
}

int main() {
	head.fill(-1);
	distance.fill(std::numeric_limits<int>::max());
	std::scanf("%d", &N);
	(void) std::exchange(serial, N);
	build((Range){1, N}, 1, FORWARD);
	build((Range){1, N}, 1, REVERSE);
	std::scanf("%d", &Q);
	while(Q --) {
		int op {};
		std::scanf("%d", &op);
		operation(op);
	}
	std::scanf("%d", &S);
	dijstra(S);
	for(int i {1}; i <= N; ++i)
		std::printf("%d", distance[i] == std::numeric_limits<int>::max() ? -1 : distance[i]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值