传送门:https://codeforces.com/problemset/problem/1051/F
注意到\(m-n\le 20\),求一个连通图中任意两点间最短路,我们不难想到将问题转换到树上。先求出树的任意一颗生成树,此时倍增或者树刨能轻松算出仅含树边的最小路径。
而对于非树边,从边的角度显然很难做到,我们不妨从点的角度思考,在非树边上的点至多有\(42\)个,我们不妨假设这些点是必经点,我们以这\(42\)个点为起点分别求出单源最短路,然后分最短路上是否存在非树边连接的点来讨论,如果存在就从特殊点出发求最短路,否则直接在树上求两点距即可,最后答案就是两者较小值。时间复杂度\(O((n+q)log_{2}n+42(n+m)logn)\)。
PS:这道题几乎用到了图论一半的知识,是道非常好的练手题。
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = true;
int res = c - '0';
while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + c - '0';
return flag ? -res : res;
}
const int N = 1e5 + 1;
struct Edge {
int v, next, w, u;
} e[N << 1], te[N << 1];
int h[N], th[N], c, tc, fa[N][21], d[N][21], dis[43][N], dep[N], vis[N], ff[N];
bool is_key[N];
vector<int> key;
void add(int u, int v, int w) {
e[c].u = u;
e[c].v = v;
e[c].w = w;
e[c].next = h[u];
h[u] = c++;
}
void tadd(int u, int v, int w) {
te[tc].v = v;
te[tc].w = w;
te[tc].next = th[u];
th[u] = tc++;
}
void dfs(int x, int f) {
dep[x] = dep[f] + 1;
fa[x][0] = f;
for (int i = 1; i <= 20; ++i) fa[x][i] = fa[fa[x][i - 1]][i - 1], d[x][i] = d[x][i - 1] + d[fa[x][i - 1]][i - 1];
for (int i = th[x]; ~i; i = te[i].next) {
int y = te[i].v, w = te[i].w;
if (y == f) continue;
d[y][0] = w;
dfs(y, x);
}
}
int getDis(int x, int y) {
int ans = 0;
if (dep[x] > dep[y]) swap(x, y);
for (int i = 20; i >= 0; --i) {
if (dep[fa[y][i]] >= dep[x]) ans += d[y][i], y = fa[y][i];
}
if (x == y) return ans;
for (int i = 20; i >= 0; --i) {
if (fa[x][i] != fa[y][i]) ans += d[x][i] + d[y][i], x = fa[x][i], y = fa[y][i];
}
return ans + d[x][0] + d[y][0];
}
void Dijkstra(int s) {
memset(vis, 0, sizeof vis);
priority_queue<pair<int, int>> q;
q.push(make_pair(0, key[s]));
dis[s][key[s]] = 0;
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = h[x]; ~i; i = e[i].next) {
int y = e[i].v;
if (dis[s][x] + e[i].w < dis[s][y]) {
dis[s][y] = dis[s][x] + e[i].w;
q.push(make_pair(-dis[s][y], y));
}
}
}
}
int get(int x) { return x == ff[x] ? x : ff[x] = get(ff[x]); }
signed main() {
memset(h, -1, sizeof h);
memset(th, -1, sizeof th);
memset(dis, 0x3f, sizeof dis);
int n = read(), m = read();
for (int i = 1; i <= n; ++i) ff[i] = i;
for (int i = 1; i <= m; ++i) {
int u = read(), v = read(), w = read();
add(u, v, w);
add(v, u, w);
}
for (int i = 0; i < c; i += 2) {
if (get(e[i].u) != get(e[i].v)) tadd(e[i].u, e[i].v, e[i].w), tadd(e[i].v,e[i].u,e[i].w), ff[get(e[i].u)] = get(e[i].v);
else {
if (!is_key[e[i].u]) key.push_back(e[i].u);
if (!is_key[e[i].v]) key.push_back(e[i].v);
is_key[e[i].u] = is_key[e[i].v] = true;
}
}
dep[1] = 1;
dfs(1, 0);
for (int i = 0; i < key.size(); ++i) Dijkstra(i);
int q = read();
while (q--) {
int u = read(), v = read();
int ans = getDis(u, v);
for (int i = 0; i < key.size(); ++i) ans = min(ans, dis[i][u] + dis[i][v]);
printf("%lld\n", ans);
}
return 0;
}
标签:dep,int,题解,void,CF1051F,fa,th,dis
From: https://www.cnblogs.com/Jefferyz/p/18445751