UVa 11354 Bond 最小生成树+LCA倍增

来源:互联网 发布:爱温士采暖知乎 编辑:程序博客网 时间:2024/05/17 23:28

题目大意: n 个点 m 条边的图 q 次询问,每条边都有一个危险系数,每次询问要求一条从 s 到 t 的路径使所有边的最大危险系数最小

思路:

先求出最小生成树,这样能保证图中所有路径的值最小。

接着dfs建有根树,记录 fa[i] 和 val[i] 分别表示节点 i 的父亲节点编号和 i 与父亲的边的权值,同时处理出深度deep[i]

利用倍增思想预处理出LCA和两点之间路径的最大权值记为 STfa[i][j] , STcost[i][j]

接着就是每次 logn 的询问了


细节看代码:

/************************************************************************* > Author: wzw-cnyali > Created Time: 2017/9/11 12:41:53 ************************************************************************/#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>#prag\ma GCC optimize("O3")using namespace std;#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)#define EREP(i, a) for(register int i = (be[a]); i != -1; i = nxt[i])#define mem(a, b) memset((a), b, sizeof(a))template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }template <class T>T read(T sum = 0, T fg = 0){char c = getchar();while(c < '0' || c > '9') { fg |= c == '-'; c = getchar(); }while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); }return fg ? -sum : sum;}const int Size = 100010;struct Edge{int x, y, w;void input(){x = read<int>();y = read<int>();w = read<int>();}friend bool operator < (Edge a, Edge b){return a.w < b.w;}}edge[Size];int to[Size], nxt[Size], be[Size], w[Size], e;void add(int x, int y, int z) { to[e] = y; nxt[e] = be[x]; be[x] = e; w[e] = z; e++; }void add_edge(int x, int y, int z) { add(x, y, z); add(y, x, z); }void init() { mem(be, -1); e = 0; }int n, m;int fa[Size];int father(int x){return fa[x] = x == fa[x] ? x : father(fa[x]);}bool merge(int x, int y){int fx = father(x), fy = father(y);if(fx != fy) { fa[fx] = fy; return 1; }else return 0;}void Kruskal(){init();REP(i, 1, n) fa[i] = i;sort(edge + 1, edge + m + 1);int count = 0;REP(i, 1, m){int x = edge[i].x, y = edge[i].y, w = edge[i].w;if(merge(x, y)){add_edge(x, y, w);if(++count == n - 1) break;}}}int deep[Size], Fa[Size], val[Size];void dfs_init(int x, int f, int depth){Fa[x] = f; deep[x] = depth;EREP(i, x){int y = to[i];if(y != f){val[y] = w[i];dfs_init(y, x, depth + 1);}}}int STfa[Size][20];int STcost[Size][20];void ST_init(){mem(STfa, -1);REP(i, 1, n){STcost[i][0] = val[i];STfa[i][0] = Fa[i];}for(int j = 1; (1 << j) <= n; ++j){REP(i, 1, n){int a = STfa[i][j - 1];if(a != -1){STfa[i][j] = STfa[a][j - 1];STcost[i][j] = max(STcost[i][j - 1], STcost[a][j - 1]);}}}}int query(int L, int R){if(deep[L] < deep[R]) swap(L, R);int lg = log2(deep[L]);int ans = -1;DREP(i, lg, 0){if(deep[L] - (1 << i) >= deep[R]){chkmax(ans, STcost[L][i]);L = STfa[L][i];}}if(L == R) return ans;DREP(i, lg, 0){if(STfa[L][i] != -1 && STfa[L][i] != STfa[R][i]){chkmax(ans, STcost[L][i]);chkmax(ans, STcost[R][i]);L = STfa[L][i]; R = STfa[R][i];}}chkmax(ans, val[L]); chkmax(ans, val[R]);return ans;}int main(){#ifndef ONLINE_JUDGEfreopen("input.in", "r", stdin);freopen("output.out", "w", stdout);#endifint Case;while(scanf("%d%d", &n, &m) != EOF){if(Case++) puts("");REP(i, 1, m) edge[i].input();Kruskal();dfs_init(1, -1, 0);ST_init();int q = read<int>();while(q--){int x = read<int>(), y = read<int>();int ans = query(x, y);printf("%d\n", ans);}}return 0;}


原创粉丝点击