題解:AT_abc362_d [ABC362D] Shortest Path 3

worker2011發表於2024-07-14

一句話題意:給定一個帶點權的有權無向連通圖,求點 1 到所有其它點的最短路徑。

首先,只有 1 一個起點,所以是單源最短路,又因為最大是 \(2 \times 10^5\),所以是優先佇列(堆)最佳化過後的 Dijkstra。

所以,我們只需要解決點權的問題就好了。一種顯而易見的想法是把與這條邊的邊權加上起終點的點權,因為走這條邊肯定是要過這兩個點的。但這樣有個問題:樣例都過不了(或許是我寫掛了?反正只過了樣例 2)!為啥呢?

你從 1 走到 2,再從 2 走到 3,你這點 2 的點權不就算重了?

那該咋辦呢?

其實你不用改邊權,對 Dijkstra 做一點小改動即可。什麼小改動呢?每次走邊的時候加上終點的點權,這樣子就方便算、判斷了。注意不能加起點的,因為起點是固定的,你算它跟沒算一樣。

比如還是從 1 到 2 再到 3,你每條邊再加上點 2、3 的點權,就不會出事了。

但注意此時點 1 的點權還沒算,輸出是加上就好。


ACCode:

// Problem: D - Shortest Path 3
// Contest: AtCoder - Toyota Programming Contest 2024#7(AtCoder Beginner Contest 362)
// URL: https://atcoder.jp/contests/abc362/tasks/abc362_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

/*Code by Leo2011*/
#include <bits/stdc++.h>

#define log printf
#define EPS 1e-8
#define INF 0x3f3f3f3f3f3f3f3f
#define FOR(i, l, r) for (ll(i) = (l); (i) <= (r); ++(i))
#define IOS                      \
	ios::sync_with_stdio(false); \
	cin.tie(nullptr);            \
	cout.tie(nullptr);

using namespace std;

typedef __int128 i128;
typedef long long ll;
typedef pair<ll, ll> PII;

const ll N = 1e6 + 10;
ll m, n, s, x, y, z, a[N], w[N], to[N], idx, dis[N], nxt[N], head[N];

struct line {
	ll u, d;
	bool operator<(const line &cmp) const { return d > cmp.d; }
};
priority_queue<line> q;

template <typename T>

inline T read() {
	T sum = 0, fl = 1;
	char ch = getchar();
	for (; !isdigit(ch); ch = getchar())
		if (ch == '-') fl = -1;
	for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - '0';
	return sum * fl;
}

template <typename T>

inline void write(T x) {
	if (x < 0) putchar('-'), write<T>(-x);
	static T sta[35];
	ll top = 0;
	do { sta[top++] = x % 10, x /= 10; } while (x);
	while (top) putchar(sta[--top] + 48);
}

inline void init() {
	memset(head, -1, sizeof(head));
	memset(dis, 0x3f, sizeof(dis));
}

inline void addEdge(ll u, ll v, ll q) {
	w[idx] = q;
	to[idx] = v;
	nxt[idx] = head[u];
	head[u] = idx;
	idx++;
}

void dijkstra(ll s) {
	dis[s] = 0;
	q.push({s, 0});
	while (!q.empty()) {
		line f = q.top();
		q.pop();
		ll u = f.u;
		if (f.d > dis[u]) continue;
		for (ll i = head[u]; i != -1; i = nxt[i]) {
			ll v = to[i];
			if (dis[u] + w[i] + a[v] < dis[v]) {
				dis[v] = dis[u] + w[i] + a[v];  // 把要去的點的點權算上
				q.push({v, dis[v]});
			}
		}
	}
}

int main() {
	init();
	n = read<ll>(), m = read<ll>(), s = 1;
	FOR(i, 1, n) a[i] = read<ll>();
	FOR(i, 1, m) {
		x = read<ll>(), y = read<ll>(), z = read<ll>();
		addEdge(x, y, z), addEdge(y, x, z);
	}
	dijkstra(s);
	FOR(i, 2, n)
	write<ll>(dis[i] + a[1]), putchar(' ');  // 除了起點都有了,所以要加上起點
	return 0;
}

AC 記錄~

理解萬歲!

相關文章