2021CCPC浙江省賽 D Shortest Path Query


可以發現可以構建出的是一棵樹,且樹的深度在20層及以內

剛開始想對於每條路徑跑最短路,然后都跑一邊得出答案,但是發現因為路徑可以重疊,所以后面求的路徑會修改一些公共路徑的最短路,所以不能這么求

考慮什么是不變的,一個點到自己的最短路一定是0,所以從每個點出發,跑它到所有子節點的最短路,這個路一定是這兩個點最終的最短路,而且因為這是一個二叉樹,所以復雜度為

\(T(n) = 2*T(n/2) + nlogn\)
大約是\(O(n(logn)^2)\)
然后對於每次詢問,找所有的公共祖先,求解即可

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
typedef pair<ll, int> P;
vector < P > edge[N];
ll f[N][30];
bool vis[N];
void cmin(ll & a, ll b) { a = min(a, b); }
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	memset(f, 0x3f, sizeof(f));
	for (int i = 1; i <= m; i++) {
		int u, v, j; ll w;
		scanf("%d%d%lld", &u, &v, &w);
		if (u > v)	swap(u, v);
		edge[u].emplace_back(v, w);
		edge[v].emplace_back(u, w);
		for (j = 0; (v >> j) != u; j++);
		cmin(f[v][j], w);
	}
	for (int i = 1; i <= n; i++) {
		priority_queue < P, vector < P >, greater < P > > Q;
		vector < int > c;
		Q.emplace(0, i);
		int j; f[i][0] = 0;
		while (!Q.empty()) {
			P u = Q.top(); Q.pop();
			if (vis[u.second])	continue;
			vis[u.second] = true; c.emplace_back(u.second);
			for (j = 0; (u.second >> j) != i; j++);
			cmin(f[u.second][j], u.first);
			for (auto x:edge[u.second]) {
				if (!vis[x.first] && x.first >= i)
					Q.emplace(u.first + x.second, x.first);
			}
		}
		for (auto x:c)	vis[x] = false;
	}
	int q; scanf("%d", &q);
	while (q--) {
		int u, v, j = 0; scanf("%d %d", &u, &v);
		ll ans = (1ll << 60);
		for (int i = 0; i < 28; i++) {
			while ((v >> i) < (u >> j))	j++;
			if ((v >> i) == (u >> j))
				cmin(ans, f[u][j] + f[v][i]);
		}
		if (ans > 60ll * 1e9)	puts("-1");
		else printf("%lld\n", ans);
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM