cf1051F. The Shortest Statement(最短路)
程序员文章站
2022-07-04 22:18:16
题意 题目链接 题意:给出一张无向图,每次询问两点之间的最短路,满足$m - n <= 20$ $n, m, q \leqslant 10^5$ Sol 非常好的一道题。 首先建出一个dfs树。 因为边数-点数非常少,所以我们可以对于某些非树边特殊考虑。 具体做法是:对于非树边连接的两个点,暴力求出 ......
题意
题意:给出一张无向图,每次询问两点之间的最短路,满足$m - n <= 20$
$n, m, q \leqslant 10^5$
sol
非常好的一道题。
首先建出一个dfs树。
因为边数-点数非常少,所以我们可以对于某些非树边特殊考虑。
具体做法是:对于非树边连接的两个点,暴力求出它们到所有点的最短路
对于询问的$(x, y)$
用树上的边,以及非树边连接的点到他们的最短路之和更新答案
由于边数的限制,非树边连接的点不会超过$2*(m - (n - 1)) = 42$个
#include<bits/stdc++.h> #define pair pair<int, int> #define mp(x, y) make_pair(x, y) #define fi first #define se second #define ll long long using namespace std; const int maxn = 2 * 1e5 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int n, m, q, head[maxn], num = 0, vis[maxn], fa[maxn][21], dep[maxn], happen[maxn]; ll dis[50][maxn], tdis[maxn]; vector<int> p; struct edge { ll u, v, w, f, nxt; }e[maxn]; inline void addedge(int x, int y, int z) { e[num] = (edge) {x, y, z, 0, head[x]}; head[x] = num++; } void dfs(int x, int _fa) { vis[x] = 1; dep[x] = dep[_fa] + 1; for(int i = head[x]; ~i; i = e[i].nxt) { int to = e[i].v; if(vis[to]) continue; e[i].f = e[i ^ 1].f = 1; tdis[to] = tdis[x] + (ll)e[i].w; fa[to][0] = x; dfs(to, x); } } void dij(int x, int id) { memset(dis[id], 0x7f, sizeof(dis[id])); dis[id][x] = 0; memset(vis, 0, sizeof(vis)); priority_queue<pair> q; q.push(mp(0, x)); while(!q.empty()) { int p = q.top().se; q.pop(); if(vis[p]) continue; for(int i = head[p]; ~i; i = e[i].nxt) { int to = e[i].v; if(dis[id][to] > dis[id][p] + e[i].w && (!vis[to])) dis[id][to] = dis[id][p] + e[i].w, q.push(mp(-dis[id][to], to)); } } } void pre() { for(int j = 1; j <= 20; j++) for(int i = 1; i <= n; i++) fa[i][j] = fa[fa[i][j - 1]][j - 1]; } int lca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); for(int i = 20; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i]; if(x == y) return x; for(int i = 20; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; return fa[x][0]; } main() { // freopen("a.in", "r", stdin); memset(head, -1, sizeof(head)); n = read(); m = read(); for(int i = 1; i <= m; i++) { int x = read(), y = read(), z = read(); addedge(x, y, z); addedge(y, x, z); } dfs(1, 0); for(int i = 0; i < num; i++) if(!e[i].f) { if(!happen[e[i].u]) p.push_back(e[i].u), happen[e[i].u] = 1; if(!happen[e[i].v]) p.push_back(e[i].v), happen[e[i].v] = 1; } for(int i = 0; i < p.size(); i++) dij(p[i], i); pre(); int q = read(); while(q--) { int x = read(), y = read(); ll ans = tdis[x] + tdis[y] - 2 * tdis[lca(x, y)]; for(int i = 0; i < p.size(); i++) ans = min(ans, dis[i][x] + dis[i][y]); cout << ans << endl; } return 0; }
上一篇: vue仿element实现分页器效果