貨車運輸(倍增 LCA 生成樹)
阿新 • • 發佈:2021-08-22
前置知識:LCA 倍增 生成樹
如果單純求出從 1 號點到** n **號點的最小且最大的那條路,只需要靈活跑一遍
最短路就可以了
然而對於求任意兩點之間的距離,上述方法就時間複雜度過大無法通過。考慮
到降低複雜度,此時選擇使用倍增的方法,是的原本O(n)的時間複雜度降低為
logn
此時問題就在於如何使用倍增方法求解距離,藉助求LCA的方法,可以得知求距離
的方法和求LCA的方法是一樣的,因此距離也就能夠求出來了
#include <bits/stdc++.h> using namespace std; const int N = 1e4 + 10; int father[N], n, m, tot, head[N], dep[N], fa[N][22], value[N][22]; bool vis[N]; struct Edge{ int u, v, next, w; }edge[N << 3], edge1[N << 3]; void add(int u, int v, int w){ edge[tot].v = v; edge[tot].w = w; edge[tot].next = head[u]; head[u] = tot ++; } int find(int x){ if(x == father[x]) return x; else return father[x] = find(father[x]); } bool cmp(Edge a, Edge b){ return a.w > b.w; } void kruskal(){ sort(edge1 + 1, edge1 + 1 + m, cmp); int cnt = 0; for(int i = 1; i <= m; i ++){ int a = edge1[i].u; int b = edge1[i].v; int aa = find(a), bb = find(b); if(aa == bb) continue; father[aa] = bb; cnt ++; add(a, b, edge1[i].w); add(b, a, edge1[i].w); if(cnt == n) return; } } void dfs(int now, int pre, int w){ vis[now] = true; dep[now] = dep[pre] + 1; fa[now][0] = pre; value[now][0] = w; for(int i = head[now]; i != -1; i = edge[i].next){ int v = edge[i].v; if(v != pre){ dfs(v, now, edge[i].w); } } } int getlca(int u, int v){ if(find(u) != find(v)){ return -1; } if(dep[u] < dep[v]) swap(u, v); int ans = 0x3f3f3f3f; while(dep[u] > dep[v]){ ans = min(ans, value[u][(int)log2(dep[u] - dep[v])]); u = fa[u][(int)log2(dep[u] - dep[v])]; } if(u == v) return ans; for(int i = 20; i >= 0; i --){ if(fa[u][i] != fa[v][i]){ ans = min(ans, value[u][i]); ans = min(ans, value[v][i]); u = fa[u][i]; v = fa[v][i]; } } ans = min(ans, min(value[u][0], value[v][0])); return ans; } int main(){ cin >> n >> m; for(int i = 1; i <= n; i ++) father[i] = i; memset(head, -1, sizeof head); for(int i = 1; i <= m; i ++){ int u, v, w; cin >> u >> v >> w; edge1[i].u = u; edge1[i].v = v; edge1[i].w = w; } kruskal(); for(int i = 1; i <= n; i ++){ if(!vis[i]){ dfs(i, 0, 0); } } for(int j = 1; j <= 20; j ++){ for(int i = 1; i <= n; i ++){ fa[i][j] = fa[fa[i][j - 1]][j - 1]; value[i][j] = min(value[i][j - 1], value[fa[i][j - 1]][j - 1]); } } int q; cin >> q; while(q --){ int a, b; cin >> a >> b; cout << getlca(a, b) << endl; } return 0; }