题意: 给定一个个点
条边的无向连通图,所有边边权均为
,
次询问,每次询问图中两点的最短路径,保证无自环与重边。
数据范围:
题解:
由于是无向连通图,一眼看上去是一个不可做题。
卡了很久很久才发现了数据范围有点不寻常,考虑最多有条多余的边,其余边可以组成一棵树。
那么如果是一棵树则可以先预处理后用,本题相较于树多了一些边,这些边可能会使得由树得到的树上两点唯一路径变得不再唯一,那么就可能会使得树上两点的路径变得更短。
那么考虑何时会导致这些边有效果:
对于一条边,如果树上两点距离大于
,则途径
这条路的所有路径都会被更新。
那么只需要用多余的边依次对树上的路径进行更新即可,即加上这条边对图进行一次最短路求解即可,由于边权为,可以直接用
。
解释:考虑多出来的边,以及本次询问的两个点
,则求
本题卡常严重,所以尽可能的优化能优化的部分。
代码:
#include<bits/stdc++.h> using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} while(isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();} return x * f; } const int N = 1e5 + 200; const int M = N << 1; const int Mdep = 20; int h[N], e[M], ne[M], idx; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } int dep[N]; int f[N][Mdep + 1]; void dfs(int u, int fa) { f[u][0] = fa; dep[u] = dep[fa] + 1; for(int i = 1; (1 << i) <= dep[u]; ++i) f[u][i] = f[f[u][i - 1]][i - 1]; for(int i = h[u]; i != -1; i = ne[i]) if(e[i] != fa) dfs(e[i], u); } int LCA(int a, int b) { if(dep[a] < dep[b]) swap(a, b); for(int k = Mdep; k >= 0; k--) if(dep[f[a][k]] >= dep[b]) a = f[a][k]; if(a == b) return a; for(int k = Mdep; k >= 0; k--) if(f[a][k] != f[b][k]) a = f[a][k], b = f[b][k]; return f[a][0]; } int dist(int a, int b) { return dep[a] + dep[b] - 2 * dep[LCA(a, b)]; } int p[N]; int find(int x) { if(x != p[x]) p[x] = find(p[x]); return p[x]; } int dis[110][N]; int q[N]; int cnt; void bfs(int fir) { ++cnt; dis[cnt][fir] = 0; int hh = 0, tt = -1; q[++tt] = fir; while(hh <= tt) { int u = q[hh++]; for(int i = h[u]; i != -1; i = ne[i]) { int v = e[i]; if(dis[cnt][v] > dis[cnt][u] + 1) { dis[cnt][v] = dis[cnt][u] + 1; q[++tt] = v; } } } } struct Node{ int x, y; }; vector<Node> sur; int main() { int n = read(), m = read(); idx = 0; memset(dis, 0x3f, sizeof dis); for(int i = 1; i <= n; i++) h[i] = -1, p[i] = i; for(int i = 1; i <= m; i++) { int a = read(), b = read(); int pa = find(a), pb = find(b); if(pa == pb) sur.push_back({a, b}); else { p[pa] = pb; add(a, b); add(b, a); } } dfs(1, 0); for(auto &t : sur) { add(t.x, t.y); add(t.y, t.x); } for(auto &t : sur) bfs(t.x); int Q = read(); while(Q--) { int a = read(), b = read(); int res = dist(a, b); for(int i = 1; i <= cnt; i++) res = min(res, dis[i][a] + dis[i][b]); printf("%d\n", res); } return 0; }